apache/pulsar · error · AuthenticationException
Invalid token string, missing attributes
Error message
Invalid token string, missing attributes
What it means
javax.naming.AuthenticationException thrown by SaslRoleToken.parse when the split token string does not contain exactly the three expected attributes u (userRole), i (session) and e (expires). parse compares the parsed key set against ATTRIBUTES and rejects any string that is missing attributes, has extra/unknown attributes, or duplicates a key (e.g. two 'u=' entries collapse to one key).
Source
Thrown at pulsar-broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/SaslRoleToken.java:192
@Override
public String toString() {
return token;
}
/**
* Parses a string into an authentication token.
*
* @param tokenStr string representation of a token.
*
* @return the parsed authentication token.
*
* @throws AuthenticationException thrown if the string representation could not be parsed into
* an authentication token.
*/
public static SaslRoleToken parse(String tokenStr) throws AuthenticationException {
Map<String, String> map = split(tokenStr);
if (!map.keySet().equals(ATTRIBUTES)) {
throw new AuthenticationException("Invalid token string, missing attributes");
}
long expires = Long.parseLong(map.get(EXPIRES));
SaslRoleToken token = new SaslRoleToken(map.get(USER_ROLE), map.get(SESSION));
token.setExpires(expires);
return token;
}
/**
* 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 {View on GitHub (pinned to 820761864e)
Solutions
- Ensure the token string is the exact output of SaslRoleToken.toString() (form u=<role>&i=<session>&e=<expires>) and is not truncated or re-encoded (check URL decode/encode round-trips)
- Verify client and broker use compatible versions so the token format (attribute keys u/i/e) matches; regenerate the token after upgrades
- Log the received tokenStr (carefully — it is sensitive) and diff its key set against {u,e,i} to identify the missing/extra attribute
- Handle AuthenticationException in the caller and reject the request, prompting the client to re-authenticate and obtain a fresh token
Example fix
// before
SaslRoleToken token = SaslRoleToken.parse(headerValue); // header may include scheme
// after
String tokenStr = headerValue;
if (tokenStr.startsWith("Bearer ")) {
tokenStr = tokenStr.substring("Bearer ".length());
}
if (tokenStr.matches("^u=[^&]*&i=[^&]*&e=[0-9]+$")) {
SaslRoleToken token = SaslRoleToken.parse(tokenStr);
} else {
throw new AuthenticationException("Invalid token string, missing attributes");
} Defensive patterns
Strategy: validation
Validate before calling
// run before SaslRoleToken.parse(tokenStr)
static boolean looksLikeToken(String tokenStr) {
if (tokenStr == null) return false;
Set<String> keys = new HashSet<>();
for (String part : tokenStr.split("&")) {
int eq = part.indexOf('=');
if (eq <= 0) return false;
keys.add(part.substring(0, eq));
}
return keys.equals(new HashSet<>(Arrays.asList("u", "i", "e")));
} Try / catch
try {
SaslRoleToken token = SaslRoleToken.parse(tokenStr);
if (token.isExpired()) {
throw new AuthenticationException("Token expired; re-authenticate");
}
} catch (AuthenticationException e) {
if (e.getMessage().contains("missing attributes")) {
// reject request, ask client to obtain a fresh token
}
throw e;
} Prevention
- Transmit the token exactly as produced by toString(); avoid extra URL encoding/decoding round-trips that corrupt '&' or '='
- Only round-trip tokens between toString() and parse(); don't hand-build token strings
- Keep broker and client on compatible versions of the token format
- Trim any header scheme/prefix before parsing
When it happens
Trigger: Calling SaslRoleToken.parse(tokenStr) with a string whose '&'-separated key set != {"u","e","i"} — e.g. a truncated token like "u=bob&e=123" missing i=, a token with an unexpected extra attribute, a duplicate key that collapses the map, or a non-token string such as an empty string or a different auth payload.
Common situations: Token truncated or corrupted in transit/storage (e.g. cut-and-paste, query-string handling dropping part of it); client sends a token produced by a different/older token format or a different authentication provider; token string stored/retrieved incorrectly (URL-encoding mangling); passing the whole HTTP header value including scheme instead of just the token.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid authentication token
- Authentication use SASL/JAAS/GSSAPI but server not have Prin
- Unrecognized SASL GSSAPI Server Callback.
- ${name} is NULL, empty or contains a '&'
- Invalid signed text:
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/ed16a07fe1258ef2.
Report an issue: GitHub.