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
- Configure a DelegatingOAuth2TokenGenerator containing both JwtGenerator and OAuth2AccessTokenGenerator (plus OAuth2RefreshTokenGenerator if refresh tokens are used).
- Align the registeredClient's TokenSettings access token format (SELF_CONTAINED vs REFERENCE) with the generators actually configured.
- Fix custom generators to return non-null for ACCESS_TOKEN contexts they claim to support.
- 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
- Always compose DelegatingOAuth2TokenGenerator(JwtGenerator, OAuth2AccessTokenGenerator, OAuth2RefreshTokenGenerator) when customizing.
- Keep RegisteredClient TokenSettings access token format consistent with available generators.
- Add a token-endpoint integration test for every grant type the server exposes.
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.