{"record":{"id":"697dc864b6f436e0","repo":"spring-projects/spring-security","slug":"server-error-697dc8","errorCode":"server_error","errorMessage":"The token generator failed to generate the access token.","messagePattern":"The token generator failed to generate the access token\\.","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":400,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2DeviceCodeAuthenticationProvider.java","lineNumber":229,"sourceCode":"\t\t\t\t.authorizationGrant(deviceCodeAuthentication);\n\t\t// @formatter:on\n\t\tif (dPoPProof != null) {\n\t\t\ttokenContextBuilder.put(OAuth2TokenContext.DPOP_PROOF_KEY, dPoPProof);\n\t\t}\n\n\t\t// @formatter:off\n\t\tOAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization)\n\t\t\t\t// Invalidate the device code as it can only be used (successfully) once\n\t\t\t\t.invalidate(deviceCode.getToken());\n\t\t// @formatter:on\n\n\t\t// ----- Access token -----\n\t\tOAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();\n\t\tOAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);\n\t\tif (generatedAccessToken == null) {\n\t\t\tOAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,\n\t\t\t\t\t\"The token generator failed to generate the access token.\", DEFAULT_ERROR_URI);\n\t\t\tthrow new OAuth2AuthenticationException(error);\n\t\t}\n\n\t\tif (this.logger.isTraceEnabled()) {\n\t\t\tthis.logger.trace(\"Generated access token\");\n\t\t}\n\n\t\tOAuth2AccessToken accessToken = OAuth2AuthenticationProviderUtils.accessToken(authorizationBuilder,\n\t\t\t\tgeneratedAccessToken, tokenContext);\n\n\t\t// ----- Refresh token -----\n\t\tOAuth2RefreshToken refreshToken = null;\n\t\tif (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN)) {\n\t\t\ttokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();\n\t\t\tOAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);\n\t\t\tif (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {\n\t\t\t\tOAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,\n\t\t\t\t\t\t\"The token generator failed to generate the refresh token.\", DEFAULT_ERROR_URI);\n\t\t\t\tthrow new OAuth2AuthenticationException(error);","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2DeviceCodeAuthenticationProvider.java#L211-L247","documentation":"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.'","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n.tokenGenerator(new JwtGenerator(encoder))  // client expects reference tokens\n// after\n.tokenGenerator(new DelegatingOAuth2TokenGenerator(\n    new JwtGenerator(encoder), new OAuth2AccessTokenGenerator()));","handlingStrategy":"try-catch","validationCode":"// assert a generator exists that can handle ACCESS_TOKEN\nOAuth2TokenContext ctx = new OAuth2TokenContextBuilder()\n    .tokenType(OAuth2TokenType.ACCESS_TOKEN)\n    .authorizationGrantType(AuthorizationGrantType.DEVICE_CODE)\n    .registeredClient(registeredClient).build();\nif (tokenGenerator.generate(ctx) == null) {\n    throw new IllegalStateException(\"No generator supports ACCESS_TOKEN for \" + registeredClient.getId());\n}","typeGuard":null,"tryCatchPattern":"try {\n    return provider.authenticate(tokenRequest);\n} catch (OAuth2AuthenticationException e) {\n    if (OAuth2ErrorCodes.SERVER_ERROR.equals(e.getError().getErrorCode())) {\n        logger.error(\"Access token generation failed; check OAuth2TokenGenerator config\");\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["oauth2","token-endpoint","access-token","token-generator"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}