Custom attributes
Custom attributes let a tenant attach its own fields to users, groups, and OUs — beyond ScaiKey's built-in profile — and optionally surface chosen ones as OIDC token claims.
Definitions vs values#
- A definition (
CustomAttributeDefinition) declares that an attribute exists for a tenant: itsname(the key/claim name),display_name,entity_type(USER/GROUP/OU),data_type(STRING,INTEGER,BOOLEAN,DATE,DATETIME,EMAIL,URL,ENUM,STRING_ARRAY), and flags:required,searchable,visible_in_ui,include_in_token. - A value is what's stored on a specific user/group/OU (in its
custom_attributes), e.g.{"cost_center": "CC-1"}.
Managing definitions#
Admin console: Custom Attributes (pick the tenant if you're a super-admin). Create/delete definitions and toggle Include in token / Visible in UI inline. Deleting a definition doesn't erase values already stored; it stops the field being offered and, if it was emitted, stops the claim.
API (tenant-scoped): GET/POST /api/v1/tenants/{tenant_id}/attributes,
PATCH/DELETE /api/v1/tenants/{tenant_id}/attributes/{id}.
Attributes as token claims#
An attribute is emitted as an OIDC claim only when all hold:
- its definition has
include_in_token = true, - its
entity_typeisUSER, - the user has a value stored for it,
- the requesting token has the
profilescope, and - the attribute name is not a reserved claim.
Reserved names are silently dropped from tokens even if flagged — anything a
consumer might read as authorization: role(s), permissions, scope(s),
is_admin / is_super_admin / …, partner_id(s), tenant_id, groups,
distribution_groups, the standard JWT registered claims (sub, iss, aud,
…), and created_at. Defining include_in_token on such a name is treated as a
configuration mistake, not a way to spoof an authorization signal.
Values from LDAP-synced tenants land in custom_attributes during sync; local
tenants set them via the user/group admin APIs.
See also Applications and, for reading claims, the external-app integration guide.