spring-projects/spring-security · error · OAuth2AuthenticationException
unsupported_grant_type
unsupported_grant_type
Error message
OAuth 2.0 Parameter: grant_type
What it means
After grant_type passes the single-value check, OAuth2TokenEndpointFilter asks the configured AuthenticationConverter to build a grant authentication. If no converter recognizes the grant_type, the filter throws an OAuth2AuthenticationException with error code 'unsupported_grant_type', which maps to an HTTP 400 'unsupported_grant_type' response as defined by OAuth 2.0.
Solutions
- Enable/registers support for the requested grant type (e.g. add OAuth2ClientCredentialsAuthenticationProvider or the token-exchange dependencies) in the authorization server security config
- Correct the grant_type spelling on the client (e.g. authorization_code, refresh_token, client_credentials)
- Check the Spring Security OAuth2 Authorization Server version supports the requested grant
Example fix
// before: server only allows authorization_code
http.oauth2AuthorizationServer(authorizationServer -> authorizationServer.tokenEndpoint(t -> t.accessTokenRequestConverter(new OAuth2AuthorizationCodeAuthenticationConverter(...))))
// after: also support client_credentials
http.oauth2AuthorizationServer(authorizationServer -> authorizationServer
.tokenEndpoint(t -> t.accessTokenRequestConverters(c -> c.add(new OAuth2ClientCredentialsAuthenticationConverter())))) Defensive patterns
Strategy: try-catch
Validate before calling
Set<String> supported = Set.of("authorization_code","refresh_token","client_credentials","urn:ietf:params:oauth:grant-type:device_code");
if (!supported.contains(grantType)) {
throw new IllegalArgumentException("grant_type not enabled on this server: " + grantType);
} Try / catch
try {
TokenResponse r = client.tokenRequest(...);
} catch (OAuth2ErrorResponseException ex) {
if ("unsupported_grant_type".equals(ex.getError().getErrorCode())) {
// fall back to a supported grant or surface a config error
}
} Prevention
- Keep server grant configuration and client grant usage in sync
- After adding a grant type, confirm the matching converter/provider is registered
- Test the token endpoint after Spring Security version upgrades
When it happens
Trigger: Requesting the token endpoint with a grant_type not enabled on the authorization server, e.g. 'password', 'client_credentials' when disabled, 'urn:ietf:params:oauth:grant-type:token-exchange' without the corresponding dependency/converter, or a typo like 'authorizationCode'.
Common situations: Authorization server not configured with the grant (e.g. missing OAuth2TokenExchangeAuthenticationProvider/converter), Spring Security version where a grant type is not yet supported, or client requesting a grant the server intentionally restricts.
Related errors
- Invalid Authorization Grant Type
- Invalid Authorization Grant Type
- invalid_dpop_proof
- invalid_request
- invalid_token_response
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/09efed2987e60de0.
Report an issue: GitHub.
Appendix: source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2TokenEndpointFilter.java:163
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (!this.tokenEndpointMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
try {
String[] grantTypes = request.getParameterValues(OAuth2ParameterNames.GRANT_TYPE);
if (grantTypes == null || grantTypes.length != 1) {
throw createException(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.GRANT_TYPE);
}
Authentication authorizationGrantAuthentication = this.authenticationConverter.convert(request);
if (authorizationGrantAuthentication == null) {
throw createException(OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE, OAuth2ParameterNames.GRANT_TYPE);
}
if (authorizationGrantAuthentication instanceof AbstractAuthenticationToken authenticationToken) {
authenticationToken.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) this.authenticationManager
.authenticate(authorizationGrantAuthentication);
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, accessTokenAuthentication);
}
catch (OAuth2AuthenticationException ex) {
SecurityContextHolder.clearContext();
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Token request failed: %s", ex.getError()), ex);
}
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
}
}
View on GitHub (pinned to 96852e8860)