apache/pulsar · error · AuthenticationException

Invalid signed text:

Error message

Invalid signed text: 

What it means

SaslRoleTokenSigner.verifyAndExtract verifies HMAC-signed strings (format: payload + SIGNATURE marker + signature). If the input string does not contain the SIGNATURE separator at all, it is not a signed string produced by sign(), so an AuthenticationException is thrown with the offending text appended.

Source

Thrown at pulsar-broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/SaslRoleTokenSigner.java:74

            throw new IllegalArgumentException("NULL or empty string to sign");
        }
        String signature = computeSignature(str);
        return str + SIGNATURE + signature;
    }

    /**
     * Verifies a signed string and extracts the original string.
     *
     * @param signedStr the signed string to verify and extract.
     *
     * @return the extracted original string.
     *
     * @throws AuthenticationException thrown if the given string is not a signed string or if the signature is invalid.
     */
    public String verifyAndExtract(String signedStr) throws AuthenticationException {
        int index = signedStr.lastIndexOf(SIGNATURE);
        if (index == -1) {
            throw new AuthenticationException("Invalid signed text: " + signedStr);
        }
        String originalSignature = signedStr.substring(index + SIGNATURE.length());
        String rawValue = signedStr.substring(0, index);
        String currentSignature = computeSignature(rawValue);
        if (!MessageDigest.isEqual(originalSignature.getBytes(), currentSignature.getBytes())){
            throw new AuthenticationException("Invalid signature");
        }
        return rawValue;
    }

    /**
     * Returns the signature of a string.
     *
     * @param str string to sign.
     *
     * @return the signature for the string.
     */
    protected String computeSignature(String str) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Ensure the string passed to verifyAndExtract() comes from SaslRoleTokenSigner.sign() (or an equivalent client using the same secret) and was not truncated
  2. Check that no intermediary (proxy, header parser) strips or mangles the signed token before it reaches the broker
  3. Log/inspect the received string to confirm where the signature part was lost

Example fix

// before
String role = signer.verifyAndExtract(rawToken); // throws if rawToken unsigned
// after
if (rawToken == null || !rawToken.contains(SaslRoleTokenSigner.SIGNATURE)) {
    throw new AuthenticationException("token missing signature");
}
String role = signer.verifyAndExtract(rawToken);
Defensive patterns

Strategy: validation

Validate before calling

if (signedStr == null || !signedStr.contains(SIGNATURE)) {
    throw new AuthenticationException("not a signed token");
}

Type guard

static boolean isSigned(String s) {
    return s != null && s.lastIndexOf(SaslRoleTokenSigner.SIGNATURE) >= 0;
}

Try / catch

try {
    String role = signer.verifyAndExtract(signedStr);
} catch (AuthenticationException e) {
    // reject request / force re-auth
}

Prevention

When it happens

Trigger: Calling verifyAndExtract() with a plain, unsigned, empty, or malformed string that lacks the signature separator (e.g. token truncated before the signature, or a value fetched from the wrong config/cookie field).

Common situations: SASL authentication handshakes where the client sent a raw role token instead of the signed one; proxy/load-balancer stripping or truncating the token; manually constructed credentials in tests or scripts.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/ba8b0d4cd73a5db7. Report an issue: GitHub.