spring-projects/spring-security · error · OAuth2AuthenticationException

server_error

server_error

Error message

The token generator failed to generate the access token.

What it means

When redeeming a device code at the token endpoint, the provider asks the composed OAuth2TokenGenerator for an access token. A null result means no generator supports the ACCESS_TOKEN token type for this grant, so a server_error OAuth2AuthenticationException is thrown with 'The token generator failed to generate the access token.'

Source

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

				.authorizationGrant(deviceCodeAuthentication);
		// @formatter:on
		if (dPoPProof != null) {
			tokenContextBuilder.put(OAuth2TokenContext.DPOP_PROOF_KEY, dPoPProof);
		}

		// @formatter:off
		OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization)
				// Invalidate the device code as it can only be used (successfully) once
				.invalidate(deviceCode.getToken());
		// @formatter:on

		// ----- Access token -----
		OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).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.", DEFAULT_ERROR_URI);
			throw new OAuth2AuthenticationException(error);
		}

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

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

		// ----- Refresh token -----
		OAuth2RefreshToken refreshToken = null;
		if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN)) {
			tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
			OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
			if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
				OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
						"The token generator failed to generate the refresh token.", DEFAULT_ERROR_URI);
				throw new OAuth2AuthenticationException(error);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Configure a DelegatingOAuth2TokenGenerator containing both JwtGenerator and OAuth2AccessTokenGenerator (plus OAuth2RefreshTokenGenerator if refresh tokens are used).
  2. Align the registeredClient's TokenSettings access token format (SELF_CONTAINED vs REFERENCE) with the generators actually configured.
  3. Fix custom generators to return non-null for ACCESS_TOKEN contexts they claim to support.
  4. Catch OAuth2AuthenticationException and return error=server_error per RFC 6749 so clients retry or re-initiate the flow.

Example fix

// before
.tokenGenerator(new JwtGenerator(encoder))  // client expects reference tokens
// after
.tokenGenerator(new DelegatingOAuth2TokenGenerator(
    new JwtGenerator(encoder), new OAuth2AccessTokenGenerator()));
Defensive patterns

Strategy: try-catch

Validate before calling

// assert a generator exists that can handle ACCESS_TOKEN
OAuth2TokenContext ctx = new OAuth2TokenContextBuilder()
    .tokenType(OAuth2TokenType.ACCESS_TOKEN)
    .authorizationGrantType(AuthorizationGrantType.DEVICE_CODE)
    .registeredClient(registeredClient).build();
if (tokenGenerator.generate(ctx) == null) {
    throw new IllegalStateException("No generator supports ACCESS_TOKEN for " + registeredClient.getId());
}

Try / catch

try {
    return provider.authenticate(tokenRequest);
} catch (OAuth2AuthenticationException e) {
    if (OAuth2ErrorCodes.SERVER_ERROR.equals(e.getError().getErrorCode())) {
        logger.error("Access token generation failed; check OAuth2TokenGenerator config");
    }
    throw e;
}

Prevention

When it happens

Trigger: OAuth2DeviceCodeAuthenticationProvider.authenticate() after successful device-code verification: tokenGenerator.generate() returns null for the ACCESS_TOKEN context (e.g. only a JwtGenerator is configured but token format is self-contained/opaque, or only opaque generator configured but token settings require JWT).

Common situations: Custom tokenGenerator() missing OAuth2AccessTokenGenerator (opaque) or JwtGenerator (reference vs self-contained mismatch); registeredClient token settings (access-token-format) not matching available generators; device-code grant enabled but the generator chain narrowed by customization.

Related errors


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