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

  1. Attach the handler only to the token endpoint (OAuth2TokenEndpointFilter) where authentication results are OAuth2AccessTokenAuthenticationToken.
  2. Inspect the handler registration in the SecurityFilterChain and move it to the correct filter's success handler.
  3. In tests, pass an OAuth2AccessTokenAuthenticationToken (with access token, etc.) instead of a mock Authentication.
  4. 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

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


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/d7173cb7fc0c380b. Report an issue: GitHub.