spring-projects/spring-security · error · IllegalArgumentException
Missing required parameter: access_token
Error message
Missing required parameter: access_token
What it means
DefaultMapOAuth2AccessTokenResponse.convert requires an access_token parameter in the token endpoint response map per RFC 6749 §5.1. If the map has no access_token, it throws IllegalArgumentException, which callers usually surface wrapped in an OAuth2AuthorizationException or conversion error.
Solutions
- Inspect the raw token endpoint response (enable HTTP logging) and fix why access_token is missing
- Check that grant_type/client credentials are correct so the server returns a real success response with HTTP 200 and access_token
- If the provider returns errors with HTTP 200, add a custom Converter<Map<String,Object>,OAuth2AccessTokenResponse> that detects error fields first and throws OAuth2ErrorException
Example fix
// before
// provider returns {"error":"invalid_grant"} with HTTP 200 -> converter fails
// after
// set a tolerant converter
converter.setAccessTokenResponseConverter(params -> {
if (params.containsKey("error")) throw new OAuth2ErrorException(new OAuth2Error((String) params.get("error")));
return defaultConvert(params);
}); Defensive patterns
Strategy: validation
Validate before calling
if (!source.containsKey(OAuth2ParameterNames.ACCESS_TOKEN)) {
throw new OAuth2AuthorizationException(new OAuth2Error("invalid_token_response", "token response missing access_token", null));
} Type guard
boolean hasAccessToken(Map<String,Object> body) {
return body != null && body.get("access_token") instanceof String s && !s.isBlank();
} Try / catch
catch (IllegalArgumentException e) {
if (e.getMessage().contains("access_token")) {
// capture raw response body for diagnosis and fail with clear message
}
} Prevention
- Check token endpoint responses with logging before production
- Confirm grant_type and credentials so the provider returns a success body
- Add a custom converter for providers that return errors with HTTP 200
When it happens
Trigger: The authorization/token endpoint returned a 200 body that lacks access_token — e.g. an error JSON body delivered with HTTP 200, an HTML error page, or a provider returning only refresh_token.
Common situations: Misconfigured token URL hitting a login page; providers deviating from the spec on device-code or extension grants; proxies returning soft-200 error pages; using this converter on a non-token payload.
Related errors
- An error occurred reading the OAuth 2.0 Access Token…
- invalid_token_response
- access_denied
- access_denied
- An error occurred reading the OAuth 2.0 Authorization…
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/6c1150ca91106ecf.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverter.java:50
/**
* A {@link Converter} that converts the provided OAuth 2.0 Access Token Response
* parameters to an {@link OAuth2AccessTokenResponse}.
*
* @author Steve Riesenberg
* @since 5.6
*/
public final class DefaultMapOAuth2AccessTokenResponseConverter
implements Converter<Map<String, Object>, OAuth2AccessTokenResponse> {
private static final Set<String> TOKEN_RESPONSE_PARAMETER_NAMES = new HashSet<>(
Arrays.asList(OAuth2ParameterNames.ACCESS_TOKEN, OAuth2ParameterNames.EXPIRES_IN,
OAuth2ParameterNames.REFRESH_TOKEN, OAuth2ParameterNames.SCOPE, OAuth2ParameterNames.TOKEN_TYPE));
@Override
public OAuth2AccessTokenResponse convert(Map<String, Object> source) {
String accessToken = getParameterValue(source, OAuth2ParameterNames.ACCESS_TOKEN);
if (accessToken == null) {
throw new IllegalArgumentException("Missing required parameter: " + OAuth2ParameterNames.ACCESS_TOKEN);
}
OAuth2AccessToken.TokenType accessTokenType = getAccessTokenType(source);
long expiresIn = getExpiresIn(source);
Set<String> scopes = getScopes(source);
String refreshToken = getParameterValue(source, OAuth2ParameterNames.REFRESH_TOKEN);
Map<String, Object> additionalParameters = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : source.entrySet()) {
if (!TOKEN_RESPONSE_PARAMETER_NAMES.contains(entry.getKey())) {
additionalParameters.put(entry.getKey(), entry.getValue());
}
}
// @formatter:off
return OAuth2AccessTokenResponse.withToken(accessToken)
.tokenType(accessTokenType)
.expiresIn(expiresIn)
.scopes(scopes)
.refreshToken(refreshToken)
.additionalParameters(additionalParameters)View on GitHub (pinned to 96852e8860)