CodamAIDocs
Topicdone

Where the tenant comes from

The six kinds of tenant assignment and the order in which policy and hook decide.

Variants
NONECREATE_NEWJOIN_EXISTINGFROM_CALLERFROM_PAYLOADFROM_INVITATIONHook overrides

What this is about

Every registration must know which tenant the person ends up in: a new one, an existing one, or none at all. This is set by the tenant assignment, configured per flow as tenant-assignment.

The six kinds

AssignmentMeaningWhere the key comes fromAllowed for
NONEno tenant–all flows
CREATE_NEWnew tenant, the person founds itfrom the payload, a hook, or derived from companyall flows
JOIN_EXISTINGjoin an existing tenantfrom the payload or a hook, requiredall flows
FROM_CALLERthe calling person’s tenantfrom their tokennot SELF_SERVICE, because there is no caller there
FROM_PAYLOADtenant named by the callerfrom the tenantKey fieldonly PLATFORM_ADMIN
FROM_INVITATIONtenant named when invitingfrom the request, requiredall flows

The rules in the last column are built in: if a configuration sets, say, FROM_PAYLOAD for SELF_SERVICE, CIAS rejects registrations in that flow.

The shipped settings

FlowAssignment in cias-runtimeEffect
SELF_SERVICECREATE_NEWevery self-registration founds a tenant
TENANT_ADMINFROM_CALLERinvitation into your own tenant
PLATFORM_ADMINnot configuredsee Creation by the platform administrator

The decision path

Who decides about the tenant?
  1. CIAS
    Policy
    tenant-assignment of the flow, plus a key from the token or payload
  2. CIAS
    FROM_CALLER?
    Then the tenant is fixed. Hooks are not asked at all
  3. Hook
    Hooks
    onResolveTenant may replace the decision, one after another
  4. CIAS
    Derive key
    CREATE_NEW without a key? Then derive it from company
  5. The tenant is fixed and is stored on the registration

This decision is made when the registration is submitted. Whether the tenant exists is checked by CIAS during provisioning. See What happens on completion.

Each kind in detail

The six assignments

When: An installation without tenants, or a flow for people without a company.

The person gets no tenant. A tenantKey in the payload is ignored. The roles come from the TENANTLESS situation.

When: Self-registration of a company.

The key is derived from the company field if neither the payload nor a hook names one: accents removed, lowercase, other characters become -, at most 48 characters. If company is missing, the domain of the address is the source, for example muster-bau from anna@muster-bau.de. If the key is taken, CIAS appends -2 to -20. During provisioning the organization and the tenant are created; the person is the founder (TENANT_FOUNDER).

When: A hook or caller knows which existing tenant the person belongs to.

Without a key this assignment is invalid. The person becomes a member (TENANT_MEMBER).

When: Invitation by a tenant administrator.

The tenant comes from their token. A tenantKey in the payload is discarded, hooks are not asked. If the caller has no tenant: 403.

When: Creation by the platform administrator.

The tenant comes from the tenantKey field. If it is missing: 400.

When: The request names the tenant the person is invited into.

As with JOIN_EXISTING, the person becomes a member of the named tenant. Without a key the assignment is invalid.

When: A project has its own rules, for example: addresses with @nordbau.example always belong to nordbau.

A hook with onResolveTenant gets the policy's decision and returns a new one, or null for “unchanged”. CIAS stores the reason on the registration. With FROM_CALLER the hook is not called.

Result: See Your own logic: hooks and events.

Next

Sources in the code and the knowledge base
  • CIAS/cias-registration – TenantAssignment, TenantDecision, RegistrationPolicy (invariants), RegistrationService (resolveTenant, deriveTenantKey, assignTenant)
  • CIAS/cias-registration – RegistrationHook.onResolveTenant, RegistrationServiceTest
  • CIAS/cias-runtime – application.yml (tenant-assignment per flow)
  • CIAS/cias-registration/docs/adr – ADR-011
Search