spring-projects/spring-security · error · OAuth2AuthenticationException

server_error

server_error

Error message

The token generator failed to generate the access token.

What it means

In the token-exchange grant flow, after validating the request the provider asks the configured OAuth2TokenGenerator to produce an access token for the built OAuth2TokenContext. A null result means no registered generator (e.g. JWT encoder or opaque-token generator) supports the context, so the provider throws server_error with this message.

Source

Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2TokenExchangeAuthenticationProvider.java:245

				.authorization(subjectAuthorization)
				.principal(principal)
				.authorizationServerContext(AuthorizationServerContextHolder.getContext())
				.authorizedScopes(authorizedScopes)
				.tokenType(OAuth2TokenType.ACCESS_TOKEN)
				.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
				.authorizationGrant(tokenExchangeAuthentication);
		// @formatter:on
		if (dPoPProof != null) {
			tokenContextBuilder.put(OAuth2TokenContext.DPOP_PROOF_KEY, dPoPProof);
		}

		// ----- Access token -----
		OAuth2TokenContext tokenContext = tokenContextBuilder.build();
		OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
		if (generatedAccessToken == null) {
			OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
					"The token generator failed to generate the access token.", ERROR_URI);
			throw new OAuth2AuthenticationException(error);
		}

		if (this.logger.isTraceEnabled()) {
			this.logger.trace("Generated access token");
		}

		// @formatter:off
		OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
				.principalName(subjectAuthorization.getPrincipalName())
				.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
				.authorizedScopes(authorizedScopes)
				.attribute(Principal.class.getName(), principal);
		// @formatter:on

		OAuth2AccessToken accessToken = OAuth2AuthenticationProviderUtils.accessToken(authorizationBuilder,
				generatedAccessToken, tokenContext);

		OAuth2Authorization authorization = authorizationBuilder.build();

View on GitHub (pinned to 96852e8860)

Solutions

  1. Configure a token generator that supports the context: set oauth2AuthorizationServerConfigurer.tokenGenerator(...) with a JwtGenerator and/or OAuth2AccessTokenGenerator
  2. Register a NimbusJwtEncoder (JWKSource-based) bean so JwtGenerator can produce self-contained access tokens
  3. Check the registered authorization's token settings (accessTokenFormat) match an available generator (JWT vs opaque/REFERENCE_TOKEN)
  4. Enable trace logging to inspect the OAuth2TokenContext and confirm which generator is expected

Example fix

// before: no generator for JWT
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
// after
NimbusJwtEncoder jwtEncoder = new NimbusJwtEncoder(jwkSource);
JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder);
jwtGenerator.setJwtCustomizer(...);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
    .tokenGenerator(jwtGenerator)
    .tokenGenerator(new OAuth2AccessTokenGenerator());
Defensive patterns

Strategy: validation

Validate before calling

// startup check: ensure a generator exists for the configured token format
OAuth2TokenContext ctx = new OAuth2TokenContext() {} // build sample access-token context
if (tokenGenerator.generate(tokenContext) == null) {
  throw new IllegalStateException("No OAuth2TokenGenerator configured for the access token format");
}

Try / catch

try {
  return tokenEndpoint.exchange(request);
} catch (OAuth2AuthenticationException e) {
  if ("server_error".equals(e.getError().getErrorCode())) {
    log.error("Token generation failed — check JwtEncoder/tokenGenerator configuration", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the token endpoint with grant_type=token_exchange when the authorization server's OAuth2TokenGenerator cannot emit a token for the requested context — typically because neither a JwtGenerator nor an OAuth2AccessTokenGenerator matches the context (e.g. no JwtEncoder configured and token format not opaque-eligible).

Common situations: Security config missing a NimbusJwtEncoder bean on OAuth2AuthorizationServerConfigurer's tokenGenerator; token exchange enabled but the default token settings (e.g. reference vs self-contained) yield no matching generator; authorization-server metadata/customizer restricting the access-token format.

Related errors


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