spring-projects/spring-security · error · OAuth2AuthorizationException
invalid_token_response
invalid_token_response
Error message
An error occurred parsing the Access Token response: ${ex.getMessage()} What it means
This OAuth2AuthorizationException with code invalid_token_response is thrown by OAuth2AccessTokenResponseBodyExtractor.parse when the access token response body cannot be parsed as JSON by Nimbus's TokenResponse. A ParseException from the raw JSON string is wrapped with an OAuth2Error describing the parse failure.
Source
Thrown at oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/web/reactive/function/OAuth2AccessTokenResponseBodyExtractor.java:84
return delegate.extract(inputMessage, context)
.onErrorMap((ex) -> new OAuth2AuthorizationException(
invalidTokenResponse("An error occurred parsing the Access Token response: " + ex.getMessage()),
ex))
.switchIfEmpty(Mono.error(() -> new OAuth2AuthorizationException(
invalidTokenResponse("Empty OAuth 2.0 Access Token Response"))))
.map(OAuth2AccessTokenResponseBodyExtractor::parse)
.flatMap(OAuth2AccessTokenResponseBodyExtractor::oauth2AccessTokenResponse)
.map(OAuth2AccessTokenResponseBodyExtractor::oauth2AccessTokenResponse);
}
private static TokenResponse parse(Map<String, Object> json) {
try {
return TokenResponse.parse(new JSONObject(json));
}
catch (ParseException ex) {
OAuth2Error oauth2Error = invalidTokenResponse(
"An error occurred parsing the Access Token response: " + ex.getMessage());
throw new OAuth2AuthorizationException(oauth2Error, ex);
}
}
private static OAuth2Error invalidTokenResponse(String message) {
return new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE, message, null);
}
private static Mono<AccessTokenResponse> oauth2AccessTokenResponse(TokenResponse tokenResponse) {
if (tokenResponse.indicatesSuccess()) {
return Mono.just(tokenResponse).cast(AccessTokenResponse.class);
}
TokenErrorResponse tokenErrorResponse = (TokenErrorResponse) tokenResponse;
ErrorObject errorObject = tokenErrorResponse.getErrorObject();
OAuth2Error oauth2Error = getOAuth2Error(errorObject);
return Mono.error(new OAuth2AuthorizationException(oauth2Error));
}
private static OAuth2Error getOAuth2Error(ErrorObject errorObject) {View on GitHub (pinned to 96852e8860)
Solutions
- Log the raw response body to see what was actually returned.
- Catch OAuth2AuthorizationException and check getError().getErrorCode() equals invalid_token_response.
- Verify the token endpoint returns application/json with token_type/access_token fields per RFC 6749 section 5.1.
- Check for proxies/gateways rewriting the response (HTML 502 pages).
- If the response was error-shaped, ensure the caller distinguishes OAuth2ErrorResponse handling from token response parsing.
Example fix
// before
TokenResponse response = OAuth2AccessTokenResponseBodyExtractor.parse(body); // throws
// after
try {
TokenResponse response = OAuth2AccessTokenResponseBodyExtractor.parse(body);
} catch (OAuth2AuthorizationException ex) {
if ("invalid_token_response".equals(ex.getError().getErrorCode())) {
logger.warn("Token endpoint returned non-JSON: {}", body);
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (body == null || body.isBlank() || !body.strip().startsWith("{")) {
throw new IllegalArgumentException("Access token response must be a JSON object");
} Try / catch
try {
TokenResponse response = OAuth2AccessTokenResponseBodyExtractor.parse(body);
} catch (OAuth2AuthorizationException ex) {
if ("invalid_token_response".equals(ex.getError().getErrorCode())) {
logger.warn("Unparseable token response: {}", body);
}
} Prevention
- Log raw token endpoint bodies to detect HTML/proxy responses.
- Confirm Content-Type is application/json before parsing.
- Treat empty bodies (already-consumed streams) as a failure before parsing.
- Use MockWebServer tests to cover malformed token responses.
When it happens
Trigger: The access token response body passed to parse is not valid JSON: empty body, HTML error page, or JSON array instead of object (JSONObject constructor or TokenResponse.parse throws ParseException).
Common situations: Authorization server/proxy returns HTML on token endpoint errors (wrong URL, 502 page), response body is empty because content was already consumed, or a mock server returns malformed JSON in tests.
Related errors
- invalid_id_token
- invalid_user_info_response
- An error occurred reading the OAuth 2.0 Device Authorization
- An error occurred writing the OAuth 2.0 Device Authorization
- An error occurred reading the OAuth 2.0 Error: ${ex.getMessa
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/c09b94890ced11d6.
Report an issue: GitHub.