apache/pulsar · error · AuthenticationException

Invalid authentication token

Error message

Invalid authentication token

What it means

javax.naming.AuthenticationException thrown by SaslRoleToken.split when a '&'-separated segment of the token string contains no '=' character, meaning it is neither a key=value attribute pair nor parseable. split tokenizes on '&' and requires each part to have at least one '='; a bare fragment (e.g. "garbage" between '&' separators, or a value that itself contained '&' from an unvalidated token) triggers this before the attribute-set check in parse.

Source

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

    /**
     * Splits the string representation of a token into attributes pairs.
     *
     * @param tokenStr string representation of a token.
     *
     * @return a map with the attribute pairs of the token.
     *
     * @throws AuthenticationException thrown if the string representation of the token could not be broken into
     * attribute pairs.
     */
    private static Map<String, String> split(String tokenStr) throws AuthenticationException {
        Map<String, String> map = new HashMap<String, String>();
        StringTokenizer st = new StringTokenizer(tokenStr, ATTR_SEPARATOR);
        while (st.hasMoreTokens()) {
            String part = st.nextToken();
            int separator = part.indexOf('=');
            if (separator == -1) {
                throw new AuthenticationException("Invalid authentication token");
            }
            String key = part.substring(0, separator);
            String value = part.substring(separator + 1);
            map.put(key, value);
        }
        return map;
    }

}

View on GitHub (pinned to 820761864e)

Solutions

  1. Regenerate the token with SaslRoleToken/toString() so it contains only valid u=, i=, e= segments separated by '&', with no empty or '='-less segments
  2. Reject or sanitize any user-supplied component containing '&' before constructing the token (enforce checkForIllegalArgument on all inputs)
  3. Validate token shape before parsing: each '&'-separated part must contain '=' (regex like ^([^&=]+=[^&]*&)*[^&=]+=[^&]*$), else re-authenticate
  4. Catch AuthenticationException in the caller and return a clear invalid-token error so the client fetches a fresh token

Example fix

// before
SaslRoleToken token = SaslRoleToken.parse(tokenStr); // tokenStr may contain "u=bob&&i=1"
// after
if (Arrays.stream(tokenStr.split("&")).anyMatch(part -> !part.contains("="))) {
    throw new AuthenticationException("Invalid authentication token");
}
SaslRoleToken token = SaslRoleToken.parse(tokenStr);
Defensive patterns

Strategy: validation

Validate before calling

// run before SaslRoleToken.parse(tokenStr)
static boolean everySegmentHasKey(String tokenStr) {
    if (tokenStr == null) return false;
    for (String part : tokenStr.split("&", -1)) {
        if (!part.contains("=")) return false; // empty or bare fragment
    }
    return true;
}

Try / catch

try {
    SaslRoleToken token = SaslRoleToken.parse(tokenStr);
} catch (AuthenticationException e) {
    if (e.getMessage().equals("Invalid authentication token")) {
        throw new AuthenticationException("Malformed token: a segment lacks '='; client must re-authenticate");
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling SaslRoleToken.parse(tokenStr) where any '&'-delimited segment lacks '=' — e.g. "u=bob&&i=1&e=9" (empty segment), "u=bob&i=1&e=9&extra" (trailing junk), or a token whose attribute value illegally contained '&' (bypassing checkForIllegalArgument) so the value split into fragments.

Common situations: Manually built or concatenated token strings; token values that legitimately contain '&' because producers skipped SaslRoleToken validation; corrupted/stored tokens with stray '&' or empty sections; clients sending arbitrary strings to the token endpoint probing the parser.

Understand the failure class

Related errors


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