{"record":{"id":"a7b131f82af5237d","repo":"spring-projects/spring-security","slug":"insufficient-scope","errorCode":"insufficient_scope","errorMessage":"insufficient_scope","messagePattern":"insufficient_scope","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":403,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcUserInfoAuthenticationProvider.java","lineNumber":107,"sourceCode":"\n\t\tOAuth2Authorization authorization = this.authorizationService.findByToken(accessTokenValue,\n\t\t\t\tOAuth2TokenType.ACCESS_TOKEN);\n\t\tif (authorization == null) {\n\t\t\tthrow new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);\n\t\t}\n\n\t\tif (this.logger.isTraceEnabled()) {\n\t\t\tthis.logger.trace(\"Retrieved authorization with access token\");\n\t\t}\n\n\t\tOAuth2Authorization.Token<OAuth2AccessToken> authorizedAccessToken = authorization.getAccessToken();\n\t\tAssert.notNull(authorizedAccessToken, \"authorizedAccessToken cannot be null\");\n\t\tif (!authorizedAccessToken.isActive()) {\n\t\t\tthrow new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);\n\t\t}\n\n\t\tif (!authorizedAccessToken.getToken().getScopes().contains(OidcScopes.OPENID)) {\n\t\t\tthrow new OAuth2AuthenticationException(OAuth2ErrorCodes.INSUFFICIENT_SCOPE);\n\t\t}\n\n\t\tOAuth2Authorization.Token<OidcIdToken> idToken = authorization.getToken(OidcIdToken.class);\n\t\tif (idToken == null) {\n\t\t\tthrow new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_TOKEN);\n\t\t}\n\n\t\tif (this.logger.isTraceEnabled()) {\n\t\t\tthis.logger.trace(\"Validated user info request\");\n\t\t}\n\n\t\tOidcUserInfoAuthenticationContext authenticationContext = OidcUserInfoAuthenticationContext\n\t\t\t.with(userInfoAuthentication)\n\t\t\t.accessToken(authorizedAccessToken.getToken())\n\t\t\t.authorization(authorization)\n\t\t\t.build();\n\t\tOidcUserInfo userInfo = this.userInfoMapper.apply(authenticationContext);\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcUserInfoAuthenticationProvider.java#L89-L125","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nString authorizeUrl = \"https://server/oauth2/authorize?response_type=code&client_id=my-client&scope=profile%20email\";\n\n// after\nString authorizeUrl = \"https://server/oauth2/authorize?response_type=code&client_id=my-client&scope=openid%20profile%20email\";","handlingStrategy":"validation","validationCode":"boolean canCallUserInfo(OAuth2AccessToken token) {\n    return token != null && token.getScopes() != null && token.getScopes().contains(\"openid\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ResponseEntity<String> info = restTemplate.getForEntity(userInfoUrl, String.class);\n} catch (HttpStatusCodeException ex) {\n    if (ex.getResponseBodyAsString().contains(\"insufficient_scope\")) {\n        token = reauthorizeWithScopes(\"openid profile email\");\n    }\n}","preventionTips":["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."],"tags":["oauth2","oidc","scope","user-info","spring-security"],"backgroundTag":"insufficient-permissions","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}