You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
8000
Repository navigation
Improve feedback on token validation when using Tokens.getAccessToken
#39525
In our custom endpoint extensions, we use Tokens.getAccessToken(session) to get the token in the request. This has one issue, when the token is invalid, the method always returns null. Since our custom endpoint is used by another service, we want to give a proper response, which is currently not possible.
The problem is not in Tokens.getAccessToken but in the underlying classes it uses. It calls AppAuthManager.BearerTokenAuthenticator.authenticate() which then in turn calls AuthenticationManager.verifyIdentityToken(). The verifyIdentityToken method silently returns null for various error scenarios without providing any context on what went wrong. Most of the time, it only logs debug logs.
Current Implementation
In AuthenticationManager.verifyIdentityToken(), error handling is implemented as returning null in many scenarios:
publicstaticAuthResultverifyIdentityToken(KeycloakSessionsession, RealmModelrealm, UriInfouriInfo,
ClientConnectionconnection, booleancheckActive, booleancheckTokenType,
StringcheckAudience, booleanisCookie, StringtokenString, HttpHeadersheaders,
Predicate<? superAccessToken>... additionalChecks) {
try {
// Token verification logic...
} catch (VerificationExceptione) {
logger.debugf("Failed to verify identity token: %s", e.getMessage());
}
returnnull; // No error information is returned
}
In our custom endpoint implementation, when we call:
val token =Tokens.getAccessToken(session)
if (token ==null) {
// We don't know why the token is invalidreturnResponse.status(Status.UNAUTHORIZED).build()
}
Possible Solutions
Option 1: Throw Exceptions Instead of Returning Null
Modify verifyIdentityToken to throw specific exceptions instead of returning null. This would provide more context about what went wrong.
publicstaticAuthResultverifyIdentityToken(KeycloakSessionsession, RealmModelrealm, UriInfouriInfo,
ClientConnectionconnection, booleancheckActive, booleancheckTokenType,
StringcheckAudience, booleanisCookie, StringtokenString, HttpHeadersheaders,
Predicate<? superAccessToken>... additionalChecks) throwsTokenVerificationException {
try {
// Token verification logic...
} catch (VerificationExceptione) {
logger.debugf("Failed to verify identity token: %s", e.getMessage());
thrownewTokenVerificationException("Token verification failed", e, TokenVerificationException.Reason.VERIFICATION_FAILED);
}
// Other error cases would throw specific exceptionsif (!token.isActive() || token.getIat() < realm.getNotBefore()) {
thrownewTokenVerificationException("Token is not active", TokenVerificationException.Reason.TOKEN_INACTIVE);
}
// Return auth result if all checks passreturnnewAuthResult(user, userSession, token, client);
}
With the introduction of a custom exception class:
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
In our custom endpoint extensions, we use
Tokens.getAccessToken(session)to get the token in the request. This has one issue, when the token is invalid, the method always returnsnull. Since our custom endpoint is used by another service, we want to give a proper response, which is currently not possible.The problem is not in
Tokens.getAccessTokenbut in the underlying classes it uses. It callsAppAuthManager.BearerTokenAuthenticator.authenticate()which then in turn callsAuthenticationManager.verifyIdentityToken(). TheverifyIdentityTokenmethod silently returnsnullfor various error scenarios without providing any context on what went wrong. Most of the time, it only logs debug logs.Current Implementation
In
AuthenticationManager.verifyIdentityToken(), error handling is implemented as returning null in many scenarios:In our custom endpoint implementation, when we call:
Possible Solutions
Option 1: Throw Exceptions Instead of Returning Null
Modify
verifyIdentityTokento throw specific exceptions instead of returning null. This would provide more context about what went wrong.With the introduction of a custom exception class:
In our custom endpoint implementation, we could then handle specific error cases:
Option 2: Use Result/Either Pattern
Modify
verifyIdentityTokento return a result object that contains either the successful result or error details.With supporting classes:
In our custom endpoint, we could then use it like:
Bonus Option
Replace debug logs with events. Debug logs cannot be used in a production environment, therefore events would be very helpful to system admins.
Compatibility Considerations
To be backwards compatible, the old implementation would call the new implementation and then return
nullfor all the newly defined errors.All reactions