{"record":{"id":"31c9314004afd3c7","repo":"apache/pulsar","slug":"failed-to-authentication-token-e-getmessage","errorCode":null,"errorMessage":"Failed to authentication token: ${e.getMessage()}","messagePattern":"Failed to authentication token: (.+?)","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java","lineNumber":273,"sourceCode":"                                \"Audiences in token: [\" + object + \"] not contains this broker: \" + audience);\n                    }\n                } else {\n                    // should not reach here.\n                    incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);\n                    throw new AuthenticationException(\"Audiences in token is not in expected format: \" + object);\n                }\n            }\n\n            var expiration = jwt.getBody().getExpiration();\n            var tokenRemainingDurationMs = expiration != null ? expiration.getTime() - new Date().getTime() : null;\n            authenticationMetricsToken.recordTokenDuration(tokenRemainingDurationMs);\n            return jwt;\n        } catch (JwtException e) {\n            if (e instanceof ExpiredJwtException) {\n                authenticationMetricsToken.recordTokenExpired();\n            }\n            incrementFailureMetric(ErrorCode.INVALID_TOKEN);\n            throw new AuthenticationException(\"Failed to authentication token: \" + e.getMessage());\n        }\n    }\n\n    private String getPrincipal(Jws<Claims> jwt) {\n        try {\n            return jwt.getBody().get(roleClaim, String.class);\n        } catch (RequiredTypeException requiredTypeException) {\n            Collection list = jwt.getBody().get(roleClaim, Collection.class);\n            Optional<String> firstEntry = list.stream().findFirst().map(Object::toString);\n            return firstEntry.orElse(null);\n        }\n    }\n\n    /**\n     * Try to get the validation key for tokens from several possible config options.\n     */\n    private Key getValidationKey(ServiceConfiguration conf) throws IOException {\n        String tokenSecretKey = (String) conf.getProperty(confTokenSecretKeySettingName);","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java#L255-L291","documentation":"authenticateToken wraps any JwtException from the jjwt parser into an AuthenticationException with this message. The underlying JwtException covers expired tokens, bad signatures, malformed JWTs, missing required claims, and null audience. If the exception is an ExpiredJwtException the provider additionally records a token-expired metric before rethrowing.","triggerScenarios":"jwt parser.parseClaimsJws(token) throws: an ExpiredJwtException (token past its exp), SignatureException (signed with the wrong key), MalformedJwtException (corrupted/invalid token string), or MissingClaimException / null audience as constructed in this method.","commonSituations":"Client presents a token signed with a key that no longer matches the broker's tokenSecretKey/tokenPublicKey; token TTL expired and the client hasn't refreshed it; token string truncated or with extra characters copied into configuration; broker switched between symmetric and asymmetric keys without updating clients.","solutions":["Read the wrapped cause message (e.getMessage()) to identify whether it is expiration, signature, or malformed-token, then address specifically.","If expired, issue a fresh token and ensure the client refreshes tokens before exp (set a TTL with margin).","If a signature error, confirm the broker's tokenSecretKey/tokenPublicKey matches the key used to sign client tokens.","If malformed, re-copy the token carefully (it must be the raw base64url JWT, usually supplied via the token parameter in client conf)."],"exampleFix":"// before: expired cached token reused by client\nAuthenticationException: Failed to authentication token: JWT expired at 2026-09-05T00:00:00Z\n// after: refresh token before expiry\nif (Instant.now().isAfter(tokenExpiry.minus(5, MINUTES))) { token = issueNewToken(); }","handlingStrategy":"try-catch","validationCode":"// Pre-check expiry before sending the token:\nString[] parts = token.split(\"\\\\.\");\norg.json.JSONObject claims = new org.json.JSONObject(\n    new String(java.util.Base64.getUrlDecoder().decode(parts[1])));\nlong exp = claims.optLong(\"exp\", Long.MAX_VALUE);\nif (System.currentTimeMillis() / 1000 >= exp) { refreshToken(); }","typeGuard":"static boolean tokenLooksUsable(String token) {\n    if (token == null) return false;\n    String[] parts = token.split(\"\\\\.\");\n    return parts.length == 3 && parts[0].matches(\"[A-Za-z0-9_-]+\")\n        && parts[1].matches(\"[A-Za-z0-9_-]+\") && parts[2].matches(\"[A-Za-z0-9_-]+\");\n}","tryCatchPattern":"try {\n    String role = authProvider.authenticate(authData);\n} catch (AuthenticationException e) {\n    String msg = e.getMessage();\n    if (msg != null && msg.contains(\"expired\")) {\n        refreshTokenAndRetry();\n    } else if (msg != null && (msg.contains(\"signature\") || msg.contains(\"JWT signature\"))) {\n        throw new IllegalStateException(\"Token signed with wrong key; check tokenSecretKey/tokenPublicKey\", e);\n    } else {\n        throw new IllegalStateException(\"Malformed or invalid token\", e);\n    }\n}","preventionTips":["Refresh tokens well before their exp (schedule refresh at ~80% of TTL).","Keep signing keys in sync between the token tooling and broker configuration; rotate together.","Store tokens via files/env vars to avoid truncation when copying long base64 strings.","Monitor the broker's authentication failure metrics for spikes indicating expired or mismatched tokens."],"tags":["jwt","authentication","token-validation"],"backgroundTag":"jwt-validation-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}