spring-projects/spring-security · error · OAuth2AuthenticationException
server_error
server_error
Error message
Unable to process the access token response.
What it means
Thrown by OAuth2AccessTokenResponseAuthenticationSuccessHandler.onAuthenticationSuccess() when the Authentication argument is not an OAuth2AccessTokenAuthenticationToken. This handler only knows how to write an access-token response, so receiving any other authentication type (e.g. an authorization-code or client-authentication token) is a programming/configuration error surfaced as OAuth2AuthenticationException with code server_error.
Source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2AccessTokenResponseAuthenticationSuccessHandler.java:76
private final Log logger = LogFactory.getLog(getClass());
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
private @Nullable Consumer<OAuth2AccessTokenAuthenticationContext> accessTokenResponseCustomizer;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
if (!(authentication instanceof OAuth2AccessTokenAuthenticationToken accessTokenAuthentication)) {
if (this.logger.isErrorEnabled()) {
this.logger.error(Authentication.class.getSimpleName() + " must be of type "
+ OAuth2AccessTokenAuthenticationToken.class.getName() + " but was "
+ authentication.getClass().getName());
}
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
"Unable to process the access token response.", null);
throw new OAuth2AuthenticationException(error);
}
OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
.tokenType(accessToken.getTokenType())
.scopes(accessToken.getScopes());
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
}
if (refreshToken != null) {
builder.refreshToken(refreshToken.getTokenValue());
}
if (!CollectionUtils.isEmpty(additionalParameters)) {
builder.additionalParameters(additionalParameters);
}View on GitHub (pinned to 96852e8860)
Solutions
- Attach the handler only to the token endpoint (OAuth2TokenEndpointFilter) where authentication results are OAuth2AccessTokenAuthenticationToken.
- Inspect the handler registration in the SecurityFilterChain and move it to the correct filter's success handler.
- In tests, pass an OAuth2AccessTokenAuthenticationToken (with access token, etc.) instead of a mock Authentication.
- If handling multiple outcomes, add a custom handler that type-checks instanceof OAuth2AccessTokenAuthenticationToken and delegates otherwise.
Example fix
// before OAuth2ClientAuthenticationFilter clientFilter = ...; clientFilter.setAuthenticationSuccessHandler(new OAuth2AccessTokenResponseAuthenticationSuccessHandler()); // wrong filter // after OAuth2TokenEndpointFilter tokenEndpoint = ...; tokenEndpoint.setAuthenticationSuccessHandler(new OAuth2AccessTokenResponseAuthenticationSuccessHandler());
Defensive patterns
Strategy: type-guard
Validate before calling
boolean isTokenSuccess(Authentication a) {
return a instanceof OAuth2AccessTokenAuthenticationToken;
} Type guard
if (authentication instanceof OAuth2AccessTokenAuthenticationToken tokenAuth) {
successHandler.onAuthenticationSuccess(request, response, tokenAuth);
} else {
log.warn("Skipping token response handler: wrong authentication type " + authentication.getClass());
} Try / catch
try {
successHandler.onAuthenticationSuccess(request, response, authentication);
} catch (OAuth2AuthenticationException e) {
if ("server_error".equals(e.getError().getErrorCode())) {
log.error("Handler attached to a filter that does not produce OAuth2AccessTokenAuthenticationToken");
}
throw e;
} Prevention
- Only register OAuth2AccessTokenResponseAuthenticationSuccessHandler on the token endpoint filter.
- Add an integration test asserting the filter chain emits OAuth2AccessTokenAuthenticationToken to the handler.
- Review wiring after spring-authorization-server upgrades for filter name/API changes.
When it happens
Trigger: Registering this success handler on a filter/endpoint that can produce non-token-success outcomes, e.g. wiring it into OAuth2ClientAuthenticationFilter or an authorization endpoint where the authenticated result is not an issued access token.
Common situations: Custom SecurityFilterChain wiring where the handler is attached to the wrong filter; upgrade of spring-authorization-server changing which filter emits OAuth2AccessTokenAuthenticationToken; tests calling onAuthenticationSuccess directly with a stub authentication.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unable to create an {OAuth2AuthorizedClientManager} bean. Ex
- invalid_dpop_proof
- invalid_scope
- oidc_provider_not_configured
- No enum constant org.springframework.security.oauth2.client.
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/d7173cb7fc0c380b.
Report an issue: GitHub.