Skip to content

Central onboarding ​

Central onboarding is the gateway-controlled completion flow used when a platform requires profile data before it receives a handoff. The identity UI (identity-web) hosts the user interface as one more step of the sign-in, while the Central Auth Gateway remains authoritative for the schema, values, completion state, and continuation of the login transaction.

This page documents the complete central-mode flow and the identity UI implementation. For the shared status model and the other onboarding modes, see Onboarding.

When the flow runs ​

A platform enters this flow when all of the following are true:

  • default_onboarding_mode is central
  • central_onboarding_enabled is true
  • the gateway-calculated onboarding status is not COMPLETE

The same page also runs for every platform, whatever its mode, while a required global profile field is missing. That is always the first step: the URL carries scope=global and the page asks only for the global fields. For a central-mode platform the gateway follows it, after resume, with the platform page described here. On either page only fields without a value are shown.

The gateway does not issue a platform handoff at this point. After the identity callback it creates an HttpOnly gateway session and redirects the browser to the identity UI of the environment that signed the user in:

text
{identity host}/env/{key}/onboarding?platform={platformKey}&resume={transactionId}
  • {identity host} is the origin of the environment's issuer, e.g. https://identity.iesf.gg for PROD or https://dev.identity.iesf.gg for DEV.
  • {key} is the environment's path key when the issuer is {identity host}/api/auth/env/{key} (an environment that shares its host), otherwise default. identity-web turns the prefix into its environment cookie and continues at /onboarding?…, so the page talks to the same environment that issued the login and non-production environments show the environment ribbon.
  • platform selects the server-managed field schema.
  • resume is the opaque UUID of the original authentication transaction. It is not proof that onboarding is complete.
  • scope=global (optional) switches the page to the global profile APIs: GET /v1/onboarding/global/requirements and PUT /v1/onboarding/global/values. Instead of the platform complete call it reads GET /v1/onboarding/global/status, then resumes; the gateway re-checks the global requirements itself.

End-to-end sequence ​

If the resume-time evaluation is still incomplete, the gateway redirects the browser back to the same onboarding page. Client-side state never bypasses this check.

Where the page finds the gateway ​

identity-web is one static build that serves every environment, so the gateway address is not compiled in. The page reads it from identity-api's environment endpoint:

http
GET /api/auth/environment
→ { "key": "PROD", …, "gatewayUrl": "https://auth.iesf.gg" }

gatewayUrl is identity-api's GATEWAY_PUBLIC_URL (an origin) or null. It never comes from the page URL, so a crafted link cannot send the form to another server. When it is null, the page explains that central sign-in is not set up and calls nothing.

Page layout ​

The step uses the sign-in design: the IESF logo and one centred card (the wide 640 px variant).

  • eyebrow One more step, title Complete your profile, and "{platformDisplayName} needs a few details before you continue."
  • schema-driven fields on a six-column grid. uiConfig.width makes a field full, half or third width from 640 px up; on phones every field is full width. TEXTAREA and MULTI_SELECT are always full width.
  • a small heading wherever a new uiConfig.section starts
  • one primary Save and continue action (Continue when the platform has no active fields)
  • a short checkmark animation after completion ("You're all set — Continuing to {platform}…"), then the browser goes to the gateway's resume endpoint

Loading and rendering requirements ​

The page requests:

http
GET /v1/onboarding/{platformKey}/requirements

The response supplies platformDisplayName, requirementVersion, active field definitions, and each field's currentValue. The page sorts fields by sortOrder and maps fieldType as follows:

API field typeControl and submitted value
TEXTText input → string
TEXTAREAMultiline input → string
NUMBERNumber input → number
BOOLEANCheckbox (its text is the field's placeholder, or "Yes") → boolean
DATEDate input → YYYY-MM-DD string
SELECTSingle select → option value
MULTI_SELECTCheckbox group → string array, in option order
COUNTRYTwo-letter text input, upper-cased while typing → country code
PHONETelephone input → international phone string; spaces, dashes, dots and brackets are removed
EMAILEmail input → string
URLURL input → string

Text values are trimmed. Empty scalar values are submitted as null; an empty multi-select is submitted as []. Canonical profile fields get the matching browser autofill hint (given-name, family-name, bday, …).

The page uses only safe schema metadata:

  • label, placeholder, and description
  • validation.minLength, validation.maxLength, validation.min, validation.max, and validation.pattern
  • options for select controls
  • uiConfig.width, uiConfig.section, and uiConfig.helpText

uiConfig is never interpreted as HTML or executable content.

Validation, save, complete, and resume ​

Before anything is sent, the page checks every field with the same rules the gateway applies (required values, length, pattern, number range, date, country code, + international phone format, e-mail, http(s) URL, known option). Problems appear under their fields; the first one receives focus. A required BOOLEAN is satisfied by either answer, exactly as on the gateway.

Submission is then deliberately sequential:

  1. Convert the form state to the documented API types.
  2. Send the complete field map to PUT /v1/onboarding/{platformKey}/values.
  3. Call POST /v1/onboarding/{platformKey}/complete.
  4. Require the returned status to be COMPLETE.
  5. Show the completion animation, then navigate the browser to GET /v1/auth/resume?transaction={transactionId}.

The page never appends completed=true or treats a successful value write as completion. The completion endpoint verifies all active required fields, and the resume endpoint repeats the server-side evaluation before issuing a handoff.

The page requires both platform and a valid resume UUID. Without them it shows "This link is incomplete" and calls nothing. Platforms that want users to edit these details later do so in their own UI (platform mode APIs).

Authentication, cookies, and CORS ​

Onboarding API calls use credentials: include and authenticate with the HttpOnly gateway cookie established during the central callback. The credential is not exposed to identity-web JavaScript.

The gateway trusts the identity UI hosts automatically: the host of IDENTITY_ISSUER and of every active identity environment's issuer are part of the CORS and cookie-write Origin allowlist, so they need no CORS_ORIGINS entry.

Deployment must satisfy all of these conditions:

  • identity-api's GATEWAY_PUBLIC_URL is the public gateway origin (https://auth.iesf.gg)
  • the identity UI hosts and the gateway are same-site (e.g. identity.iesf.gg, dev.identity.iesf.gg and auth.iesf.gg all under iesf.gg), because the gateway cookie is SameSite=Lax and is not sent on cross-site requests
  • credentialed CORS responses return the exact allowed origin, not *
  • production uses HTTPS

For local development, note that identity.localhost and localhost are different sites, so a gateway on http://localhost:8080 does not receive its cookie from a page on http://identity.localhost:3100. Run the gateway on a host under the identity host (for example auth.identity.localhost) when you test the full flow in a browser.

Error and retry behavior ​

FailureUser-visible behavior
platform or resume missing or malformed"This link is incomplete", no gateway call
gatewayUrl not configured"This step isn't available", no gateway call
Requirements cannot be loaded (network, 5xx)"We couldn't load this step" with Try again
Gateway session missing or expired (401)"Your sign-in has expired": go back to the app and sign in again
Field fails the client-side rulesMessage under the field, field shakes, focus moves to the first problem; nothing is sent
Value validation fails at the gateway (400)Form message; a field named in the error details is marked; entered values remain
Schema changed while filling in (404 on save)Form message asking to reload the page
Completion returns incomplete (409)User remains on the form with an error
Resume evaluation is incompleteGateway redirects back to the same onboarding page

No failed request is treated as a successful completion, and values are never replaced with mock data.

Operational setup ​

Before testing a central flow:

  1. Register the platform and its callback/return URL pairs in Card Admin.
  2. Set its default onboarding mode to central.
  3. Enable central onboarding.
  4. Add and activate the required field definitions in /admin/onboarding.
  5. Set identity-api's GATEWAY_PUBLIC_URL, and make sure the identity environment's issuer is active in the gateway.
  6. Start authentication through /v1/auth/start for that platform.

Changing an active field definition increments the platform requirementVersion. Previously complete users become IN_PROGRESS and will see central onboarding again on their next central-mode authentication when they no longer satisfy the current schema.

Security invariants ​

  • The platform key and onboarding policy come from the server-side registry.
  • The gateway address comes from identity-api configuration, never from the page URL.
  • The resume transaction must be bound to the authenticated gateway-session user and to the same identity environment.
  • The identity UI never creates a handoff code.
  • Only the gateway can mark the current requirement version complete.
  • Resume re-checks the active platform, transaction, user, and onboarding state.
  • Profile fields update canonical profile storage; custom fields remain platform-scoped.
  • The gateway token and one-time handoff code are never stored in browser-readable application state.