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

  1. Log the raw response body to see what was actually returned.
  2. Catch OAuth2AuthorizationException and check getError().getErrorCode() equals invalid_token_response.
  3. Verify the token endpoint returns application/json with token_type/access_token fields per RFC 6749 section 5.1.
  4. Check for proxies/gateways rewriting the response (HTML 502 pages).
  5. 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

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


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