apereo/cas · warning
CAS cannot use [ ] as the principal attribute id, since the…
Error message
CAS cannot use [{}] as the principal attribute id, since the profile attributes do not contain the attribute. Either adjust the CAS configuration to use a different attribute, or contact the authentication provider noted by [{}] to release the expected attribute to CAS What it means
BaseDelegatedClientAuthenticationHandler.determinePrincipalIdFrom warns when the CAS-level principalAttributeId (handler configuration) is non-blank but the pac4j profile does not contain that attribute. CAS cannot derive the principal id from it and keeps the default identifier; the message advises fixing CAS config or asking the provider to release the attribute.
Solutions
- Make the provider release the configured attribute (OIDC scopes/claims, OAuth scopes, SAML attribute release/filtering policy).
- Change cas.authn.pac4j...principal-attribute-id to an attribute the provider actually returns (verify by logging profile.getAttributes()).
- Remove the principal-attribute-id setting so the provider's default identifier is used.
Example fix
// before cas.authn.pac4j.core.principal-attribute-id=upn // after cas.authn.pac4j.core.principal-attribute-id=email
Defensive patterns
Strategy: validation
Validate before calling
if (StringUtils.isNotBlank(principalAttributeId) && !profile.containsAttribute(principalAttributeId)) {
throw new IllegalStateException("Configured principal attribute " + principalAttributeId + " missing from provider profile: " + profile.getAttributes());
} Prevention
- Prefer provider-specific principal-attribute-id settings over one global attribute.
- Test delegated login per provider after changing attribute configuration.
When it happens
Trigger: cas.authn.pac4j.core.principal-attribute-id (or equivalent handler setting) is set, profile.containsAttribute(principalAttributeId) is false during determinePrincipalIdFrom after provider authentication.
Common situations: Global principal attribute configured for all providers but only some IdPs release it; provider changed claim names (e.g. Azure AD userPrincipalName vs mail); attribute not requested in scopes; typo in configuration.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Authentication cannot find attribute
- No custom principal attribute was provided by the client
- Delegated authentication has failed with client
- Client name for [ ] is set to a generated value of [ ]…
- Service access for [ ] is denied
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/f73c4d6b55f50d80.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-pac4j-core-clients/src/main/java/org/apereo/cas/support/pac4j/authentication/handler/support/BaseDelegatedClientAuthenticationHandler.java:132
id = firstAttribute.get().toString();
id = typePrincipalId(id, profile);
}
LOGGER.debug("Authentication indicates usage of client principal attribute [{}] for the identifier [{}]", principalAttribute, id);
} else {
LOGGER.warn("Authentication cannot find attribute [{}] to use as principal id", principalAttribute);
}
} else {
LOGGER.warn("No custom principal attribute was provided by the client [{}]. Using the default id [{}]", client, id);
}
} else if (StringUtils.isNotBlank(principalAttributeId)) {
if (profile.containsAttribute(principalAttributeId)) {
val firstAttribute = CollectionUtils.firstElement(profile.getAttribute(principalAttributeId));
if (firstAttribute.isPresent()) {
id = firstAttribute.get().toString();
id = typePrincipalId(id, profile);
}
} else {
LOGGER.warn("CAS cannot use [{}] as the principal attribute id, since the profile attributes do not contain the attribute. "
+ "Either adjust the CAS configuration to use a different attribute, or contact the authentication provider noted by [{}] "
+ "to release the expected attribute to CAS", principalAttributeId, profile.getAttributes());
}
LOGGER.debug("Authentication indicates usage of attribute [{}] for the identifier [{}]", principalAttributeId, id);
} else if (isTypedIdUsed) {
id = profile.getTypedId();
LOGGER.debug("Authentication indicates usage of typed profile id [{}]", id);
}
LOGGER.debug("Final principal id determined based on client [{}] and user profile [{}] is [{}]", profile, client, id);
return id;
}
private String typePrincipalId(final String id, final UserProfile profile) {
return isTypedIdUsed
? profile.getClass().getName() + Pac4jConstants.TYPED_ID_SEPARATOR + id
: id;
}
View on GitHub (pinned to e7288fc434)