spring-projects/spring-security · error · OAuth2AuthorizationException

invalid_token_response

invalid_token_response

Error message

Empty OAuth 2.0 Access Token Response

What it means

The token endpoint returned a 2xx response whose body deserialized to null or nothing usable, so the client cannot build an OAuth2AccessTokenResponse. Spring Security throws this as invalid_token_response because an OAuth2 access token response must contain at least an access_token.

Source

Thrown at oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractRestClientOAuth2AccessTokenResponseClient.java:98

	private Consumer<MultiValueMap<String, String>> parametersCustomizer = (parameters) -> {
	};

	AbstractRestClientOAuth2AccessTokenResponseClient() {
	}

	@Override
	public OAuth2AccessTokenResponse getTokenResponse(T grantRequest) {
		Assert.notNull(grantRequest, "grantRequest cannot be null");
		try {
			// @formatter:off
			OAuth2AccessTokenResponse accessTokenResponse = this.requestEntityConverter.convert(grantRequest)
					.retrieve()
					.body(OAuth2AccessTokenResponse.class);
			// @formatter:on
			if (accessTokenResponse == null) {
				OAuth2Error error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
						"Empty OAuth 2.0 Access Token Response", null);
				throw new OAuth2AuthorizationException(error);
			}
			return accessTokenResponse;
		}
		catch (RestClientException ex) {
			OAuth2Error error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
					"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: "
							+ ex.getMessage(),
					null);
			throw new OAuth2AuthorizationException(error, ex);
		}
	}

	private RequestHeadersSpec<?> validatingPopulateRequest(T grantRequest) {
		validateClientAuthenticationMethod(grantRequest);
		return populateRequest(grantRequest);
	}

	private void validateClientAuthenticationMethod(T grantRequest) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Verify client-registration token-uri points at the actual OAuth2 token endpoint returning application/json.
  2. Curl the token endpoint manually to confirm it returns a JSON body with access_token.
  3. Check intermediaries (proxies, gateways) that might return 200 with an empty body.
  4. If you control the server, fix it to return a proper token response instead of an empty 200.

Example fix

// before
.registration.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
  .tokenUri("https://auth.example.com/api")
// after
.registration.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
  .tokenUri("https://auth.example.com/oauth2/token")
Defensive patterns

Strategy: validation

Validate before calling

// before login, sanity-check the token endpoint
HttpHeaders h = new HttpHeaders();
ResponseEntity<String> probe = rest.exchange(tokenUri, HttpMethod.POST, new HttpEntity<>(h), String.class);
if (!probe.getHeaders().getContentType().isCompatibleWith(MediaType.APPLICATION_JSON)) {
    throw new IllegalStateException("tokenUri does not return JSON: " + probe.getHeaders().getContentType());
}

Try / catch

catch (OAuth2AuthenticationException | OAuth2AuthorizationException ex) { if ("invalid_token_response".equals(ex.getError().getErrorCode())) { log.error("Token endpoint returned empty body; check tokenUri/proxies"); } throw ex; }

Prevention

When it happens

Trigger: Thrown in getTokenResponse() when RestClient.retrieve().body(OAuth2AccessTokenResponse.class) returns null — i.e., empty body on a successful (non-error) HTTP status from the token endpoint.

Common situations: Misconfigured token endpoint URL pointing at a health-check or HTML page that returns 200 with an empty/undecodable body; a proxy stripping the body; a custom server returning 200 with an empty payload instead of the JSON token response.

Related errors


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