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

  1. Include the `openid` scope in the authorization request (scope=openid ...) so the issued access token contains it.
  2. Verify the client's registered scopes (RegisteredClient.getScopes()) include "openid" and that it was not filtered out during consent.
  3. Issue a fresh access token after fixing the scopes; existing tokens keep their old scope set.
  4. 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

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.