apache/pulsar · error · AuthenticationException
Authentication has not completed
Error message
Authentication has not completed
What it means
AuthenticationStateOpenID.getAuthRole() returns the authenticated role extracted from the validated JWT, which is stored only after authenticateAsync() successfully validates the token. If getAuthRole() is called before authentication has completed (role is still null), the state throws AuthenticationException("Authentication has not completed"). It is a lifecycle/ordering guard: the broker framework (or custom code) asked for the authenticated identity too early in the connection handshake.
Source
Thrown at pulsar-broker-auth-oidc/src/main/java/org/apache/pulsar/broker/authentication/oidc/AuthenticationStateOpenID.java:54
private AuthenticationDataSource authenticationDataSource;
private volatile String role;
private final SocketAddress remoteAddress;
private final SSLSession sslSession;
private volatile long expiration;
AuthenticationStateOpenID(
AuthenticationProviderOpenID provider,
SocketAddress remoteAddress,
SSLSession sslSession) {
this.provider = provider;
this.remoteAddress = remoteAddress;
this.sslSession = sslSession;
}
@Override
public String getAuthRole() throws AuthenticationException {
if (role == null) {
throw new AuthenticationException("Authentication has not completed");
}
return role;
}
@Deprecated
@Override
public AuthData authenticate(AuthData authData) throws AuthenticationException {
// This method is not expected to be called and is subject to removal.
throw new AuthenticationException("Not supported");
}
@Override
public CompletableFuture<AuthData> authenticateAsync(AuthData authData) {
final String token = new String(authData.getBytes(), UTF_8);
this.authenticationDataSource = new AuthenticationDataCommand(token, remoteAddress, sslSession);
return provider
.authenticateTokenAsync(authenticationDataSource)
.thenApply(jwt -> {View on GitHub (pinned to 820761864e)
Solutions
- Ensure the authentication handshake completes before reading the role: check state.isComplete() first, and only then call getAuthRole().
- Make sure the client is actually sending its token (Authorization: Bearer <token> / authData) so authenticateAsync() runs and sets the role.
- If orchestrating manually, wait for the CompletableFuture returned by authenticateAsync() to complete before calling getAuthRole().
- Verify token validation is not failing silently upstream (check broker logs for JWT/JWKS/issuer errors that leave role null).
Example fix
// before
String role = authState.getAuthRole();
// after
if (authState.isComplete()) {
String role = authState.getAuthRole();
} else {
// wait for authenticateAsync() to finish or reject the connection
} Defensive patterns
Strategy: validation
Validate before calling
if (authState.isComplete()) {
String role = authState.getAuthRole();
} else {
// defer: wait for authenticateAsync() to finish before reading the role
} Type guard
boolean hasAuthRole(AuthenticationState state) {
return state.isComplete(); // role != null for AuthenticationStateOpenID
} Try / catch
try {
String role = authState.getAuthRole();
} catch (AuthenticationException e) {
// authentication not finished: re-run handshake or reject connection
} Prevention
- Always gate getAuthRole() behind isComplete().
- Drive authentication exclusively through authenticateAsync() and read the role in its thenApply/thenAccept callback.
- Log/reject connections that reach role lookup without a completed handshake — it signals a client that never sent a token.
When it happens
Trigger: Calling getAuthRole() on an AuthenticationStateOpenID instance before authenticateAsync() has completed successfully — e.g. calling it during the initial connection setup before the client sent its token, calling it after a failed or still-pending token validation future, or calling it synchronously while the async validation is still in flight.
Common situations: Broker plugins or protocol handlers that call getAuthRole() before checking AuthenticationState.isComplete(); a client that connects but never sends a Bearer token, so validation never runs; slow IdP discovery/JWKS fetch delaying completion while the broker polls for the role; a failed JWT validation leaving role null and then a retry path reading the role anyway.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Not supported
- ERROR_VERIFYING_JWT
- ERROR_RETRIEVING_PUBLIC_KEY
- Malformed JWKS returned by:
- UNSUPPORTED_ISSUER
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/6dd3c41ada4f1ee1.
Report an issue: GitHub.