CodamAIDocs
Topicdone

One flow, four variants

Self-registration, creation by the platform administrator, invitation by the tenant administrator, and redeeming the invitation: what stays the same and what differs.

Variants
SELF_SERVICEPLATFORM_ADMINTENANT_ADMINRedeem an invitationnew address / known addresswith / without approval

What this is about

In CIAS a person always becomes a user through the same flow. There are several variants, but no separate programs. The variants differ only in their policy: who may start the registration, which fields are required, where the tenant comes from, whether someone has to approve, and how long the link is valid. Each policy is in the configuration of the installation.

Why only one flow? Four copies of “check, create account, assign tenant, grant roles, notify, log” would drift apart over time. The copy that drifts is then the one that no longer enforces tenant isolation.

The variants side by side

Who starts it, where does the tenant come from?
SELF_SERVICEPLATFORM_ADMINTENANT_ADMINRedeem an invitation
Who starts it?the person themselvesplatform administratortenant administratorthe invited person
EndpointPOST /cias/registration/selfPOST /cias/admin/registrationsPOST /cias/tenant/registrationsPOST /cias/registration/invitations/accept
Sign-in needed?no, publicyes, with the roles from the policyyes, as shipped: role tenant-adminno, the link is the proof of identity
Tenant comes fromthe policy, as shipped: new tenant; a hook may change itthe policy, for example the payload (allowed only here)the caller's token, never the payloadthe invitation
Typical casea company signs up for the applicationsupport creates an access by handan administrator invites a colleaguethe colleague accepts the invitation

TENANT_ADMIN and redeeming belong together: one sends the invitation, the other redeems its link. Which variants an installation offers is in its configuration. cias-runtime offers SELF_SERVICE and TENANT_ADMIN, the hub only SELF_SERVICE. An installation must first turn on PLATFORM_ADMIN, see Creation by the platform administrator.

The shared flow

All variants go through the same states. Only the entry and the approval differ.

stateDiagram-v2
    direction LR
    [*] --> PENDING_VERIFICATION: request accepted,<br/>email with link sent
    PENDING_VERIFICATION --> VERIFIED: link clicked<br/>(or admin confirms)
    VERIFIED --> PENDING_APPROVAL: approval needed
    VERIFIED --> PROVISIONING: no approval needed
    PENDING_APPROVAL --> APPROVED: approved
    PENDING_APPROVAL --> REJECTED: rejected
    APPROVED --> PROVISIONING
    PROVISIONING --> COMPLETED: tenant, roles,<br/>welcome email
    PROVISIONING --> FAILED: error
    FAILED --> PROVISIONING: retry
    PENDING_VERIFICATION --> EXPIRED: expired, replaced, discarded
    PENDING_APPROVAL --> EXPIRED: expired, replaced, discarded
    COMPLETED --> [*]

The states of a registration explains all states and transitions.

What happens the same way in every variant
  1. 1
    CIAS
    checks whether the variant is turned on and whether the caller has the required roles; for SELF_SERVICE it also checks the throttling
  2. 2
    CIAS
    determines the tenant and checks the fields against the variant's field description
    A required field is missing or a hook rejects: 422
  3. 3
    CIAS→Keycloak
    for a new address, creates the account disabled and unverified. For a known address, the account stays untouched
  4. 4
    CIAS
    creates a one-time link. Only its hash is stored
  5. 5
    CIAS→Email
    sends its own email. Which one depends on whether the address is new
  6. 6
    User→CIAS
    clicks the link
  7. 7
    CIAS
    Approval needed? Then the registration waits in PENDING_APPROVAL
  8. 8
    CIAS→Keycloak
    enables a new account, assigns the tenant, grants the initial roles
  9. 9
    CIAS→Email
    sends the welcome email; for a new account, if possible with a link to set the password
    Result: Registration COMPLETED, the person can sign in

Each variant in the flow

The variants step by step

When: Someone registers without signing in, through the public form.

  1. 1
    User→CIAS
    fills in the form: email, name, company. No password
  2. 2
    CIAS
    checks the throttling (at most a few attempts per address)
  3. 3
    CIAS→User
    answers 202 { "status": "accepted" }, no matter whether the address is new or known
  4. 4
    CIAS→Email
    New address: verification email. Known address: an email that uses the existing account
  5. 5
    User→CIAS
    clicks the link
  6. 6
    CIAS
    waits for approval by a platform administrator, if the policy requires it
  7. 7
    CIAS
    creates a new tenant, key taken from the company name. The person gets the founder roles

Result: New tenant, the first person in it with the roles of the situation TENANT_FOUNDER. See Self-registration.

When: A platform administrator creates an access by hand.

  1. 1
    Admin→CIAS
    POST /cias/admin/registrations with email, fields and optionally tenantKey
  2. 2
    CIAS
    checks the roles from required-caller-roles, for example platform-admin
  3. 3
    CIAS
    determines the tenant by the policy, with FROM_PAYLOAD from the payload. Only this variant may do that
  4. 4
    CIAS→Email
    email with link to the person
  5. 5
    User→CIAS
    clicks the link, then provisioning as always

Result: See Creation by the platform administrator.

When: A tenant administrator invites someone into their own tenant.

  1. 1
    Admin→CIAS
    POST /cias/tenant/registrations with email and name
  2. 2
    CIAS
    checks the role (as shipped: tenant-admin)
  3. 3
    CIAS
    takes the tenant from their token. A tenantKey in the payload is ignored, not even checked
  4. 4
    CIAS→Email
    Email with link. In cias-runtime it is valid for 14 days

Result: Invitation sent, the registration waits in PENDING_VERIFICATION. See Invitation by the tenant administrator.

When: The invited person accepts the invitation.

  1. 1
    User→CIAS
    opens the link. GET /invitations/{token}/form returns the fields the inviting person left open
  2. 2
    User→CIAS
    POST /invitations/accept with the link token
  3. 3
    CIAS
    Link unknown or expired? 404. Already redeemed? The same answer as the first time
  4. 4
    CIAS
    joins the tenant from the invitation, grants the member roles

Result: The person is a member of the inviting person's tenant. See Redeem an invitation.

New or known address

In CIAS the email address is the account. There is one account per address and any number of tenant memberships. That is why every variant forks at the same point:

Which email does the person get?
Account for the address?Is there a tenant to join?Email and consequence
no–VERIFY_EMAIL – new account
yesyesMEMBERSHIP_INVITATION – joining another tenant. Password and account stay untouched
yesnoALREADY_REGISTERED – “You already have an account”, with a sign-in link

The variant’s policy sets how long the link in the email is valid (token-ttl): in cias-runtime 24 hours for self-registration, 14 days for the invitation.

From the outside all three cases look the same: same status, same answer. Only the email differs. This way nobody can find out through the API whether an account exists for an address. More on this in The email is the account.

Where the tenant comes from

The tenant is determined in two stages:

Who decides about the tenant?
  1. CIAS
    Policy of the variant
    e.g. SELF_SERVICE → new tenant, TENANT_ADMIN → from the token
  2. Hook
    Hook of the project
    may override the policy, except when the tenant comes from the token (FROM_CALLER)
  3. The tenant is fixed. Provisioning checks whether it exists

Where the tenant comes from explains all six kinds of assignment (NONE, CREATE_NEW, JOIN_EXISTING, FROM_CALLER, FROM_PAYLOAD, FROM_INVITATION).

Which roles the person gets

A rule set per situation decides this:

SituationApplies toRoles in the default setting
TENANT_FOUNDERfirst person of a new tenanttenant-owner, tenant-admin, tenant-user (client roles)
TENANT_MEMBERjoining an existing tenanttenant-user (client role)
TENANTLESSregistration without a tenantuser (realm role)

The default setting is a bean in the application’s code. Platform and tenant administration can replace it with their own rules. How that works and who may do it is described in Initial roles as a rule set.

What the answer reveals (and what it does not)

Public and administrative endpoints answer differently
public
/self, /verify, /invitations/…
  • accepted: always 202 with accepted
  • second click: 202 again
  • unknown or expired link: 404
  • no state, no ID
  • throttling: 429 without a wait time
administrative
/cias/admin/…, /cias/tenant/…
  • the caller is known
  • state and ID visible
  • list of all registrations with a filter by state
  • 403 if the role is missing

Details in Protecting the public endpoints.

The endpoints at a glance

Method and pathVariantPurpose
GET /cias/registration/flows/{flow}/formallfield description for the form
POST /cias/registration/selfSELF_SERVICEregister
POST /cias/registration/verifyallredeem the link
GET /cias/registration/invitations/{token}/forminvitationopen fields of the invitation
POST /cias/registration/invitations/acceptinvitationaccept the invitation (redeem the link)
POST /cias/admin/registrationsPLATFORM_ADMINcreate a person
POST /cias/tenant/registrationsTENANT_ADMINinvite a person
GET /cias/admin/registrationsalllist, filter by state
POST /cias/admin/registrations/{id}/approve · reject · retry · activate · discardallapproval and maintenance, platform administrator only
GET · PUT · DELETE /cias/admin/registration-rules/…allrules for the initial roles
Sources in the code and the knowledge base
  • documentation/45-identitaet/01-registrierung.md
  • CIAS/cias-registration – RegistrationService, RegistrationFlow, RegistrationState, RegistrationPolicy, RegistrationController, RegistrationAdminController
  • CIAS/cias-registration/docs/adr – ADR-011, ADR-012, ADR-014, ADR-029
  • CIAS/cias-runtime/src/main/resources/application.yml, hub-backend/src/main/resources/application.yaml
Search