CodamAIDocs
Topicdone

The path into the token

Profile in Keycloak, claim mapper, claim in the token, attribute in the RequestContext.

Variants
one valueseveral valuesno valuevalue per tenant

What this is about

For an attribute filter in CDMS to read a value, the value has to travel a long way: from the account in Keycloak through the token into the RequestContext. The RequestContext is the object in which CIAS records, for every request, who is asking, with which roles and which attributes.

The route

sequenceDiagram
    participant M as Module
    participant C as CIAS
    participant K as Keycloak
    participant B as Browser/BFF
    participant D as CDMS
    M->>C: registers region (declaration)
    C->>K: profile: region allowed
    C->>K: module's client: mapper region → claim region
    Note over C,K: once, during reconciliation
    C->>K: admin writes region = nord, west on the account
    B->>K: log in or renew the token
    K-->>B: token with "region": ["nord", "west"]
    B->>D: request with token
    D->>C: check token (filter chain)
    C->>C: claim region → attribute, insert value per tenant if needed
    C-->>D: RequestContext: effectiveUserAttributes.region = [nord, west]
    D->>D: attribute filter: region IN (nord, west)

The stations

StationWhat happens thereWho takes care of it
User profileKeycloak only stores attributes that are in the profile. It also says whether it is a list and who may change itthe reconciliation, from the registration
Value on the accountthe actual value of the personan administrator via POST /cias/admin/users/{id}/profile-attributes, for a preference also the person themselves
Claim mapperan entry on the client that says: “Put the attribute region into the token as claim region.” It applies to access token, ID token and UserInfothe reconciliation, per module on its client
Tokenthe claim is in the token. For a list as a JSON array, otherwise as textKeycloak, on every login and renewal
RequestContextCIAS turns every remaining claim into an attribute, always as a list of texts. If the attribute is registered per tenant, CIAS inserts the value of the active tenantCIAS, on every request
FilterCDMS reads the attribute from effectiveUserAttributesCDMS

The mapper sits on the module’s client, that is, the client whose token the module checks. Which claims CIAS takes as an attribute at all and which not is described in What is read from the token.

The variants

What arrives in the token and in the RequestContext

When: Attribute without multivalued, the account has customerId = 4711.

The token contains "customerId": "4711". CIAS turns it into a list with one entry.

Result: effectiveUserAttributes.customerId = ["4711"]

When: Attribute with multivalued, the account has nord and west.

The token contains "region": ["nord", "west"]. The filter also splits each entry at commas, so nord,west in one entry works the same.

Result: effectiveUserAttributes.region = ["nord", "west"]

When: The person has no value, and the attribute has no default value.

Keycloak leaves the claim out. The attribute is missing in the RequestContext. An attribute filter in CDMS then refuses the request instead of returning everything.

Result: 422 missing-attribute-on-profile for a filtered model

When: The attribute is registered as USER_IN_TENANT.

After the tenant check, CIAS fetches the person's values for the active tenant and inserts them for this key. They replace the value from the token, they are not mixed in. Only keys the application itself registers per tenant are replaced, all others come unchanged from the token.

Result: see One value per person or per tenant

Where it can get stuck

Why does my attribute not arrive?
In the profile?Mapper on the client?Value on the account?New token fetched?Result
no–––Keycloak accepts no value. Does a module register the attribute? Did the reconciliation run?
yesno––value is on the account but not in the token. Does the module run with the right client?
yesyesno–no claim, CDMS answers 422
yesyesyesnoold token without the new value
yesyesyesyesarrives

Pitfalls

Next

Sources in the code and the knowledge base
  • CIAS/cias-iam-keycloak – KeycloakAttributeAdapter (ensureAttributes, ensureClaim, mapper: oidc-usermodel-attribute-mapper, claim.name, id/access/userinfo token claim, multivalued)
  • CIAS/cias-authorization – RoleReconciliationService (writeProfile, deliver)
  • CIAS/cias-authentication – TokenParser (extractIdentity, admit, boundAttributesFor), EffectiveAttributes.resolve, AttributeLookup
  • CIAS/cias-user – UserAdminController.writeProfileAttributes (POST /cias/admin/users/{id}/profile-attributes)
  • CDMS – AbstractAttributeFilter (missing-attribute-on-profile, *)
  • CIAS/cias-authentication/docs/adr – ADR-042
Search