spring-projects/spring-security · error · OAuth2AuthenticationException
insufficient_scope
insufficient_scope
Error message
insufficient_scope
What it means
The OIDC UserInfo endpoint's authentication provider rejects a request whose access token is active but does not carry the `openid` scope. The UserInfo endpoint is part of the OpenID Connect 1.0 layer, so Spring Security requires proof that the user consented to OIDC authentication (the openid scope) before releasing claims. It throws OAuth2AuthenticationException with error code `insufficient_scope` per RFC 6750 semantics.
Source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcUserInfoAuthenticationProvider.java:107
OAuth2Authorization authorization = this.authorizationService.findByToken(accessTokenValue,
OAuth2TokenType.ACCESS_TOKEN);
if (authorization == null) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with access token");
}
OAuth2Authorization.Token<OAuth2AccessToken> authorizedAccessToken = authorization.getAccessToken();
Assert.notNull(authorizedAccessToken, "authorizedAccessToken cannot be null");
if (!authorizedAccessToken.isActive()) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
if (!authorizedAccessToken.getToken().getScopes().contains(OidcScopes.OPENID)) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INSUFFICIENT_SCOPE);
}
OAuth2Authorization.Token<OidcIdToken> idToken = authorization.getToken(OidcIdToken.class);
if (idToken == null) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Validated user info request");
}
OidcUserInfoAuthenticationContext authenticationContext = OidcUserInfoAuthenticationContext
.with(userInfoAuthentication)
.accessToken(authorizedAccessToken.getToken())
.authorization(authorization)
.build();
OidcUserInfo userInfo = this.userInfoMapper.apply(authenticationContext);
View on GitHub (pinned to 96852e8860)
Solutions
- Include the `openid` scope in the authorization request (scope=openid ...) so the issued access token contains it.
- Verify the client's registered scopes (RegisteredClient.getScopes()) include "openid" and that it was not filtered out during consent.
- Issue a fresh access token after fixing the scopes; existing tokens keep their old scope set.
- If the endpoint is not meant to be OIDC UserInfo, call a plain resource endpoint instead of /userinfo with this token.
Example fix
// before String authorizeUrl = "https://server/oauth2/authorize?response_type=code&client_id=my-client&scope=profile%20email"; // after String authorizeUrl = "https://server/oauth2/authorize?response_type=code&client_id=my-client&scope=openid%20profile%20email";
Defensive patterns
Strategy: validation
Validate before calling
boolean canCallUserInfo(OAuth2AccessToken token) {
return token != null && token.getScopes() != null && token.getScopes().contains("openid");
} Try / catch
try {
ResponseEntity<String> info = restTemplate.getForEntity(userInfoUrl, String.class);
} catch (HttpStatusCodeException ex) {
if (ex.getResponseBodyAsString().contains("insufficient_scope")) {
token = reauthorizeWithScopes("openid profile email");
}
} Prevention
- Always request scope=openid for OIDC flows and assert the issued token's scope set before calling /userinfo.
- Keep client registered scopes and requested scopes in sync in configuration/tests.
- Never reuse client_credentials tokens for the UserInfo endpoint.
When it happens
Trigger: A GET/POST to the userInfoEndpoint while authenticating with an access token whose stored OAuth2Authorization has a scope set that does not contain OidcScopes.OPENID ("openid") — e.g. the token was issued via client_credentials or a custom authorization whose granted scopes omit openid.
Common situations: Developers request a token with scope="profile email" but forget "openid", then call /userinfo; client_credentials or custom grant types minted tokens used against UserInfo; a test client's registered scopes were changed after the token was issued; tokens issued by a non-OIDC flow are mistakenly reused for UserInfo.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/a7b131f82af5237d.
Report an issue: GitHub.