{"record":{"id":"9cd1e916bce00270","repo":"apereo/cas","slug":"missing-scope-s-unable-to-authenticate-access","errorCode":null,"errorMessage":"Missing scope [%s]. Unable to authenticate access token %s","messagePattern":"Missing scope \\[(.+?)\\]\\. Unable to authenticate access token (.+?)","errorType":"exception","errorClass":"CredentialsException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oauth-uma-core/src/main/java/org/apereo/cas/uma/web/authn/BaseUmaTokenAuthenticator.java","lineNumber":40,"sourceCode":" *\n * @author Misagh Moayyed\n * @since 6.0.0\n */\n@RequiredArgsConstructor(access = AccessLevel.PROTECTED)\n@Slf4j\npublic abstract class BaseUmaTokenAuthenticator implements Authenticator {\n    private final TicketRegistry ticketRegistry;\n\n    private final JwtBuilder accessTokenJwtBuilder;\n\n    @Override\n    public Optional<Credentials> validate(final CallContext callContext, final Credentials creds) {\n        val credentials = (TokenCredentials) creds;\n        val token = extractAccessTokenFrom(credentials.getToken().trim());\n        val at = ticketRegistry.getTicket(token, OAuth20AccessToken.class);\n        if (!at.getScopes().contains(getRequiredScope())) {\n            val err = String.format(\"Missing scope [%s]. Unable to authenticate access token %s\", getRequiredScope(), token);\n            throw new CredentialsException(err);\n        }\n        val profile = new CommonProfile();\n        val authentication = at.getAuthentication();\n        val principal = authentication.getPrincipal();\n        profile.setId(principal.getId());\n        val attributes = new LinkedHashMap<String, Object>(authentication.getAttributes());\n        attributes.putAll(principal.getAttributes());\n\n        profile.addAttributes(attributes);\n        profile.addRoles(at.getScopes());\n        profile.addAttribute(OAuth20AccessToken.class.getName(), at);\n        profile.addAttribute(OAuth20Constants.CLIENT_ID, at.getClientId());\n\n        LOGGER.debug(\"Authenticated access token [{}]\", profile);\n        credentials.setUserProfile(profile);\n        return Optional.of(credentials);\n    }\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oauth-uma-core/src/main/java/org/apereo/cas/uma/web/authn/BaseUmaTokenAuthenticator.java#L22-L58","documentation":"BaseUmaTokenAuthenticator.validate extracts the UMA access token from the request, looks it up in the ticket registry as an OAuth20AccessToken, and requires that the token carries the configured required UMA scope (e.g. uma_protection). If the token's scopes do not include it, a CredentialsException is thrown and the request is not authenticated. This enforces that only protection-scoped tokens may call UMA protection endpoints.","triggerScenarios":"Presenting an OAuth2 access token to a UMA endpoint whose grant did not request/include the required scope (e.g. token issued without 'uma_protection'), typically at the permission or resource-set registration endpoints.","commonSituations":"Clients requesting tokens without the uma_protection scope in the authorization request; CAS service definition narrowing the allowed scopes; using a regular API token instead of one minted for UMA protection.","solutions":["Request the required scope (default 'uma_protection') in the OAuth2 authorization/token request.","Check which scope BaseUmaTokenAuthenticator is configured with and add it to the client's allowed scopes.","Issue a new access token after fixing the scope request; existing tokens cannot be amended.","Verify the service definition's supported scopes/evaluator are not stripping the scope at grant time."],"exampleFix":"// before\ngithub-like client: GET /oauth2.0/authorize?client_id=c&response_type=code&scope=read\n// after\nGET /oauth2.0/authorize?client_id=c&response_type=code&scope=read%20uma_protection","handlingStrategy":"try-catch","validationCode":"OAuth20AccessToken at = ticketRegistry.getTicket(token, OAuth20AccessToken.class);\nif (at == null || !at.getScopes().contains(\"uma_protection\")) {\n    throw new CredentialsException(\"token lacks uma_protection scope\");\n}","typeGuard":null,"tryCatchPattern":"try { authenticator.validate(callContext, creds); } catch (CredentialsException e) {\n    return Optional.empty(); // results in 401 with WWW-Authenticate\n}","preventionTips":["Always request uma_protection (or your configured required scope) when minting tokens for UMA clients","Document required scopes in client onboarding","Verify scopes in the token immediately after issuance in tests"],"tags":["uma","oauth","access-token","missing-scope","authentication"],"backgroundTag":"authentication-required","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}