{"record":{"id":"e7bf445da4da2a7d","repo":"apache/pulsar","slug":"invalid-token","errorCode":"INVALID_TOKEN","errorMessage":"Athenz Role Token Not Authenticated from Client: %s","messagePattern":"Athenz Role Token Not Authenticated from Client: (.+?)","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-auth-athenz/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderAthenz.java","lineNumber":166,"sourceCode":"\n            // Synchronize for non-thread safe static calls inside athenz library\n            synchronized (this) {\n                PublicKey ztsPublicKey = AuthZpeClient.getZtsPublicKey(token.getKeyId());\n\n                if (ztsPublicKey == null) {\n                    errorCode = ErrorCode.NO_PUBLIC_KEY;\n                    throw new AuthenticationException(\"Unable to retrieve ZTS Public Key\");\n                }\n\n                if (token.validate(ztsPublicKey, allowedOffset, false, null)) {\n                    log.debug().attr(\"roleToken\", roleToken)\n                            .attr(\"clientAddress\", clientAddress)\n                            .log(\"Athenz Role Token Authenticated for Client\");\n                    authenticationMetrics.recordSuccess();\n                    return token.getPrincipal();\n                } else {\n                    errorCode = ErrorCode.INVALID_TOKEN;\n                    throw new AuthenticationException(\n                            String.format(\"Athenz Role Token Not Authenticated from Client: %s\", clientAddress));\n                }\n            }\n        } catch (AuthenticationException exception) {\n            incrementFailureMetric(errorCode);\n            throw exception;\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n    }\n\n    @VisibleForTesting\n    int getAllowedOffset() {\n        return this.allowedOffset;\n    }\n}","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-auth-athenz/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderAthenz.java#L148-L184","documentation":"AuthenticationProviderAthenz validates the Athenz role token (ZTS-issued, signed ZTS header) presented by a client. When the token's signature or claims fail verification against the trusted Athenz domain/public key, the provider returns a non-authenticated result and throws this AuthenticationException with ErrorCode.INVALID_TOKEN. The message includes only the client address, never the token, to avoid leaking credentials.","triggerScenarios":"A client sends an 'Athenz' authorization header whose role token fails validation in verifyAthenzRoleTokenAndReturnPrincipal (bad/expired token, wrong domain, signature check failure) during authenticate() of an inbound connection.","commonSituations":"Client configured with an expired or rotated role token; token fetched from the wrong Athenz domain/service; ZTS public key changed on the broker but clients cache old tokens; clock skew between client and broker making token look expired; misconfigured athenz.conf or missing ZTS public key file on the broker.","solutions":["Regenerate/refresh the client's Athenz role token (it is short-lived; ensure the client refetches from ZTS before expiry)","Verify the client's principal/role is defined in the correct Athenz domain and the broker trusts the matching ZTS public key (check the ZTS public key file configured on the broker)","Check clock synchronization (NTP) between client, broker, and ZTS so token validity windows line up","Confirm the client sends the token in the expected format: 'Athenz' + space + role-token in the Authorization header, with the role token's signed header version matching the ZTS key version"],"exampleFix":"// before (client caches token forever)\nString token = loadTokenFromDisk();\nrequest.setHeader(\"Athenz\", token);\n// after (refresh before use)\nRoleToken token = ztsClient.getRoleToken(domain, null);\nif (token.getToken() != null && !isExpired(token)) {\n    request.setHeader(\"Athenz\", token.getToken());\n}","handlingStrategy":"validation","validationCode":"// client-side: ensure a fresh role token before connecting\nRoleToken rt = zts.getRoleToken(domain, null);\nInstant expiry = Instant.ofEpochMilli(rt.getExpiryTime() * 1000);\nif (Instant.now().isAfter(expiry.minus(Duration.ofMinutes(1)))) {\n    rt = zts.getRoleToken(domain, Duration.ofHours(1));\n}","typeGuard":"boolean isUsableAthenzToken(RoleToken t) {\n    return t != null && t.getToken() != null\n        && Instant.ofEpochMilli(t.getExpiryTime() * 1000).isAfter(Instant.now());\n}","tryCatchPattern":"try {\n    authData = provider.authenticate(authDataSource);\n} catch (AuthenticationException e) {\n    if (String.valueOf(e.getMessage()).contains(\"Not Authenticated\")) {\n        refreshTokenAndReconnect();\n    } else {\n        throw e;\n    }\n}","preventionTips":["Refresh role tokens proactively before expiry; Athenz tokens are short-lived","Keep broker and ZTS public keys in sync after key rotation","Run NTP on client, broker, and ZTS hosts","Verify the domain/role the token was requested for matches what the broker authorizes"],"tags":["auth","athenz","invalid-token","broker"],"backgroundTag":"invalid-auth-token","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}