CodamAIDocs
Topicdone

What is read from the token

Which claim goes where in the RequestContext: user, name, realm roles, business roles, organization, tenant, allowed tenants, attributes.

Variants
user and namerealm roles and business rolesgroupsorganization and tenantallowed tenantsattributesprotocol claims (not read)

What this is about

A token is a JSON document with claims: named entries like sub (who), exp (until when) or realm_access (which roles). CIAS reads the claims from the exchanged token and puts the results into the RequestContext. CDMS reads from there, and only from there.

From the token to the RequestContext

flowchart LR
    subgraph T["Exchanged token"]
      sub["sub"]
      name["name / preferred_username"]
      rr["realm_access.roles"]
      cr["resource_access.(client).roles"]
      grp["groups"]
      org["organization"]
      ten["tenant"]
      at["allowedTenants"]
      oth["projects, …"]
    end
    subgraph R["RequestContext"]
      uid["userId"]
      un["userName"]
      err["effectiveUserRealmRoles"]
      eur["effectiveUserRoles"]
      eug["effectiveUserGroups"]
      ut["userTenant"]
      alt["allowedTenants"]
      eua["effectiveUserAttributes"]
    end
    sub --> uid
    name --> un
    rr --> err
    cr --> eur
    org -. "roles in the tenant replace" .-> eur
    grp --> eug
    org --> ut
    ten --> ut
    at --> alt
    org --> alt
    oth --> eua

The table

Claim in the tokenSettingEnds up inNote
subclaims.user-iduserIdthe ID of the account in Keycloak
name, otherwise preferred_usernameclaims.user-nameuserNamethe first one that has a value
realm_access.rolesclaims.realm-roleseffectiveUserRealmRolesalways apply, in every tenant
resource_access.<client>.rolesclaims.client-roleseffectiveUserRolesonly its own client. Roles in the tenant can replace them
groupsclaims.groupseffectiveUserGroupsthe groups, as Keycloak writes them into the token
organizationorganization.claimuserTenant, allowedTenants, roles in the tenantthe alias of an organization is the tenant key
tenantclaims.tenant-attributeuserTenantthe static way to the tenant, first value
allowedTenantsclaims.allowed-tenants-attributeallowedTenantslist, split at commas
all others–effectiveUserAttributesas a list of strings

All settings are under codamai.cias.token. If you rename a claim, you set the new name here.

Each variant

What CIAS makes of which claim

When: for every token with a person

sub becomes the userId. This is what CDMS stores in _userId and in the history. The name comes from name or, if that is missing, from preferred_username. A service account has no name and is therefore called service-account-<client>.

When: for every token

Realm roles from realm_access.roles go unchanged to effectiveUserRealmRoles. Business roles come from resource_access.<client>.roles, and only for the own client of CIAS. The roles of other clients in the token are not read.

Result: How roles in the tenant replace the business roles: Effective roles.

When: when Keycloak writes groups into the token

The groups claim becomes effectiveUserGroups. The roles from groups are already in their places in the token anyway; the groups themselves are only there for information.

When: for dynamic tenants

The organization claim says which organizations the person is a member of and which roles they have there. CIAS understands three forms: a list of aliases, an object with the alias as key, or a list of objects with the alias under alias or name. Entries without an alias are dropped. The alias is the tenant key.

Result: Which tenant results from this: Determine the tenant of a request.

When: in operating mode MULTI

allowedTenants in the RequestContext is a list in a fixed order: first the person's own tenant, then all organizations of the person, then the values of the allowedTenants attribute, split at commas. In SINGLE the list is empty.

Result: The list decides the tenant switch via header.

When: for every other claim

Every claim that is not in the table above and is not a protocol claim becomes an attribute, such as projects. The value always becomes a list of strings: a single value becomes a list with one entry. Objects and nested lists are skipped. If an attribute is registered per tenant, the value from CIAS replaces the one from the token.

Result: What CDMS uses the attributes for: Attribute filter.

When: claims that belong to the protocol

These claims do not become attributes: iss, sub, aud, exp, nbf, iat, jti, typ, azp, nonce, auth_time, acr, amr, sid, session_state, scope, client_id and similar ones, the profile claims like name, email, preferred_username, locale, plus realm_access, resource_access, allowed-origins, groups and organization.

Result: So an email address in the token is not an attribute for a filter.

An example

exchanged token (excerpt)
{
  "sub": "7f3c…",
  "preferred_username": "anna",
  "name": "Anna Berg",
  "realm_access": { "roles": ["offline_access"] },
  "resource_access": { "cdms-backend": { "roles": ["hr-employee-read"] } },
  "organization": { "nordbau": { "id": "a1b2…" } },
  "projects": ["alpha", "beta"],
  "email": "anna@nordbau.example"
}
RequestContext
userId                  = 7f3c…
userName                = Anna Berg
userTenant              = nordbau
allowedTenants          = [nordbau]
effectiveUserRealmRoles = [offline_access]
effectiveUserRoles      = [hr-employee-read]
effectiveUserAttributes = { projects: [alpha, beta] }

email is a protocol claim and does not become an attribute. projects does.

Next

Sources in the code and the knowledge base
  • CIAS/cias-authentication – TokenParser (extractIdentity, admit, buildAllowedTenants, PROTOCOL_CLAIMS), CiasTokenProperties (Claims, Organization), KeycloakOrganizationClaimReader, ClaimValues
  • CIAS/cias-kernel – AuthenticatedIdentity
  • commons – RequestContext, RequestContextHolder
Search