{"record":{"id":"d78cdd76bbd43fff","repo":"apereo/cas","slug":"individual-claims-requested-by-openid-scopes-are-f","errorCode":null,"errorMessage":"Individual claims requested by OpenID scopes are forced to be included in the ID token. This is a violation of the OpenID Connect specification and a workaround via dedicated CAS configuration. Claims should be requested from the userinfo/profile endpoints in exchange for an access token.","messagePattern":"Individual claims requested by OpenID scopes are forced to be included in the ID token\\. This is a violation of the OpenID Connect specification and a workaround via dedicated CAS configuration\\. Claims should be requested from the userinfo/profile endpoints in exchange for an access token\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/OidcIdTokenGeneratorService.java","lineNumber":175,"sourceCode":"        val attributes = authentication.getAttributes();\n        claims.setStringClaim(OAuth20Constants.CLIENT_ID, context.getRegisteredService().getClientId());\n\n        val authTime = accessToken.isStateless() || accessToken.getTicketGrantingTicket() == null\n            ? authentication.getAuthenticationDate().toEpochSecond()\n            : ((AuthenticationAwareTicket) accessToken.getTicketGrantingTicket()).getAuthentication().getAuthenticationDate().toEpochSecond();\n        claims.setClaim(OidcConstants.CLAIM_AUTH_TIME, authTime);\n\n        if (attributes.containsKey(OAuth20Constants.STATE)) {\n            setClaim(claims, OAuth20Constants.STATE, attributes.get(OAuth20Constants.STATE).getFirst());\n        }\n        if (attributes.containsKey(OAuth20Constants.NONCE)) {\n            setClaim(claims, OAuth20Constants.NONCE, attributes.get(OAuth20Constants.NONCE).getFirst());\n        }\n        generateAccessTokenHash(accessToken, oidcRegisteredService, claims);\n\n        if (context.getResponseType() == OAuth20ResponseTypes.ID_TOKEN || includeClaimsInIdTokenForcefully(context)) {\n            FunctionUtils.doIf(includeClaimsInIdTokenForcefully(context),\n                    _ -> LOGGER.warn(\"Individual claims requested by OpenID scopes are forced to be included in the ID token. \"\n                        + \"This is a violation of the OpenID Connect specification and a workaround via dedicated CAS configuration. \"\n                        + \"Claims should be requested from the userinfo/profile endpoints in exchange for an access token.\"))\n                .accept(claims);\n            collectIdTokenClaims(principal, context.getRegisteredService(), claims);\n        } else {\n            LOGGER.debug(\"Per OpenID Connect specification, individual claims requested by OpenID scopes \"\n                + \"such as profile, email, address, etc. are only put \"\n                + \"into the OpenID Connect ID token when the response type is set to id_token.\");\n        }\n        claims.setStringClaim(OidcConstants.TXN, UUID.randomUUID().toString());\n\n        if (context.getGrantType() == OAuth20GrantTypes.CIBA) {\n            generateCibaClaims(context, claims);\n        }\n\n        Optional.ofNullable(accessToken.getAuthentication().getSingleValuedAttribute(OAuth20Constants.CLAIM_ACT, Map.class))\n            .ifPresent(value -> claims.setClaim(OAuth20Constants.CLAIM_ACT, value));\n        return claims;","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/token/OidcIdTokenGeneratorService.java#L157-L193","documentation":"Per the OpenID Connect spec, individual claims requested via scope values must come from the userinfo endpoint, not be embedded in the ID token. CAS can be configured to force scope-derived claims into the ID token as a non-compliant workaround; this warning logs each time that mode is active and claims are collected into the token.","triggerScenarios":"buildJwtClaims runs with includeClaimsInIdTokenForcefully(context) returning true (the force-include ID token claims configuration is enabled); collectIdTokenClaims then adds scope-derived principal claims and the warning fires.","commonSituations":"Administrator enabled the 'include claims in ID token' property to satisfy a legacy client that cannot call userinfo; migrating an old OAuth2 client that expects all attributes in the token; a copied service template/environment carries the workaround flag.","solutions":["Disable the force-include configuration property so claims are served from the userinfo endpoint.","Update the client to fetch claims from the userinfo endpoint using the issued access token.","If the client truly cannot call userinfo, keep the flag but document the accepted spec deviation.","Scope the flag to the specific registered service rather than globally to limit non-compliance."],"exampleFix":"// before (application.yml)\ncas:\n  authn:\n    oidc:\n      id-token:\n        include-id-token-claims: true\n// after\ncas:\n  authn:\n    oidc:\n      id-token:\n        include-id-token-claims: false","handlingStrategy":"validation","validationCode":"// Detect the non-compliant configuration before relying on spec behavior:\nboolean claimsForcedIntoIdToken(org.springframework.core.env.Environment env) {\n    return env.getProperty(\"cas.authn.oidc.id-token.include-id-token-claims\", Boolean.class, false);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Leave the force-include flag disabled unless a legacy client requires it.","Prefer userinfo-endpoint claim retrieval in client integrations.","Scope the flag per registered service rather than globally.","Document the deviation in deployment documentation when enabled."],"tags":["oidc","spec-violation","id-token","configuration"],"backgroundTag":"invalid-config-value","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"}