Skip to content

Admin operations (IESF Card) ​

Central Auth stores platforms and onboarding schemas. The IESF Card Account Center exposes the operator UI that writes those records through the Central admin APIs.

This page documents the Card admin flows as implemented today. It is not a substitute for the platform BFF integration checklist.

Access ​

RequirementDetail
AppIESF Card (Account Center)
Routes/admin/platforms, /admin/onboarding
PermissionSession must include platforms:admin: the user signed in through the deployment (PROD) identity environment and holds the local platform_admin role (snapshotted into the gateway session at login; see Identity operations)

Without a session, Card redirects to login. Without platforms:admin, Card redirects to /. A role granted while the operator is signed in takes effect at the next login.

1. Register a platform key ​

Open Platform Admin at /admin/platforms. Expand Register a new platform.

Form fields (as sent to POST /v1/platforms) ​

UI fieldBackend fieldRules
Platform keyplatformKeyUppercased on submit; must match ^[A-Z][A-Z0-9_]{1,63}$ (example: IESF_COMPETITIONS)
Display namedisplayNameRequired human label
Identity environmentidentityEnvironmentKeyIdentity environment (issuer) the platform's users sign in through; defaults to the deployment PROD environment. Managed through /v1/identity-environments
Return URL → callback URL pairsredirectPairsRequired, at least one. One row per deployment host: a return URL root (allowlists returnTo) and the BFF callback that receives the handoff for it. Exactly one pair is the default for root-relative returnTo. Production environments require public HTTPS URLs
Default onboarding modedefaultOnboardingModecentral (default in the form), platform, or none
Central onboarding enabledcentralOnboardingEnabledCheckbox; must be on when mode is central
Platform onboarding pathplatformOnboardingPathOptional path for platform-hosted onboarding UI
MetadatametadataJSON object (default {})

Click Register platform.

What happens next ​

  1. Central creates an active platform row and generates one BFF key per redirect pair.
  2. Card shows a one-time banner: Save these credentials now with the clientId and clientSecret of every pair.
  3. Each secret is shown only once. Store it in the secret manager of the deployment that serves that pair's callback; never leave it in the browser.
  4. Hand the platformKey, environment, redirect pairs, onboarding mode, and the keys to the platform team so they can implement Platform integration.

Credentials ​

A platform has two kinds of keys, managed in the Credentials section of each platform:

KindHow manyCan doUse it for
BFF keyOne per redirect pairExchange the handoff codes sent to its pair's callback; introspectThe BFF deployment behind that callback (production, staging, localhost…)
Backend keyAt most one per platformIntrospect only (403 on exchange)A server-side API (for example a Go backend) that checks gatewayTokens; it needs no registered URL
  • Because a code is bound to the callback it was sent to, a leaked localhost key cannot redeem production logins. Pairs that share the same callback URL (for example / and /admin on one BFF) share that callback's key; only one of them needs a key.
  • A pair without a usable key shows No key and its logins are refused with 409 PLATFORM_CREDENTIALS_NOT_CONFIGURED at /v1/auth/start. A newly added pair has no key until you click Generate key after saving.
  • Rotate issues a new secret, shown once. The previous secret keeps working for 60 minutes, so the deployment can be updated without downtime. Click Revoke old secret once it has switched, or immediately if the secret leaked.
  • Revoke deletes a key; it stops working at once. An active platform keeps at least one BFF key.
  • Editing a pair's URLs keeps its key. Removing a pair revokes its key (Card asks for confirmation).
  • Every change is audited (platform.credential_created, …_rotated, …_previous_secret_revoked, …_revoked; removed pairs appear as revokedCredentials on platform.updated).

Ongoing platform actions on the same page ​

For each registered platform Card also supports:

  • Save changes → PATCH /v1/platforms/{platformKey}
  • Deactivate / Activate → DELETE / POST …/activate
  • Archive (inactive platforms only) → POST …/archive. Platforms are never deleted: archiving hides the platform from the list and revokes all of its keys, while memberships, onboarding values, onboarding fields and audit history stay and the platform key remains reserved. Card asks you to type the platform key. Tick Show archived platforms instead to see them and Restore one (POST …/restore); it comes back inactive and without keys, so generate keys before activating it.
  • Credentials → POST …/credentials, POST …/credentials/{credentialId}/rotate, DELETE …/credentials/{credentialId}/previous-secret, DELETE …/credentials/{credentialId} (see Credentials)

An active platform must keep at least one return/callback URL pair, a BFF key, and an active identity environment. Changing a platform's environment asks you to type the platform key and is recorded as platform.environment_changed in the audit log.

The former callbackUrl / allowedReturnUrls fields are gone: requests that send them are rejected (400) and responses no longer include them. Use redirectPairs.

Example create body:

json
{
  "platformKey": "IESF_COMPETITIONS",
  "displayName": "IESF Competitions",
  "identityEnvironmentKey": "PROD",
  "redirectPairs": [
    { "label": "Production", "returnUrl": "https://competition.iesf.gg/", "callbackUrl": "https://competition.iesf.gg/api/auth/callback", "isDefault": true }
  ],
  "defaultOnboardingMode": "central",
  "centralOnboardingEnabled": true,
  "platformOnboardingPath": "/onboarding",
  "metadata": {}
}

Responses carry identityEnvironment: { key, displayName, tier, active } instead of an environment key; the list endpoint filters with ?identityEnvironmentKey=. An unknown key returns 400 IDENTITY_ENVIRONMENT_NOT_FOUND.

Identity environments ​

The PROD environment mirrors the IDENTITY_* deployment configuration and is read-only. Further environments (for example DEV, TEST) are registered through /v1/identity-environments: key, tier, issuer, the gateway's OIDC client ID and secret, optional post-logout redirect URI. Run validate before binding platforms to it. The full procedure is in Identity operations.

An environment cannot be deactivated while active platforms use it, and its tier cannot change while platforms are bound to it.

Users and platform admins ​

/v1/admin/users lists gateway users (searchable by e-mail, filterable by environment), grants or removes platform_admin (PROD users only) and revokes all sessions of a user. See Identity operations.

2. Onboarding Admin — dynamic schema ​

Open Onboarding Admin at /admin/onboarding.

Global profile requirements (all platforms) ​

The first card lists every canonical profile field (first name, last name, date of birth, nationality, …) with two switches:

  • Collect adds the field to the global requirements (POST /v1/admin/onboarding/global-fields, or PATCH active=true to restore it). Turning it off archives it (DELETE …/{profileFieldKey}); saved profile values are kept.
  • Required makes the field mandatory for signing in to any platform.

Details opens the editor for the label, description, placeholder, sort order, options, validation and UI config. The type list offers only the types the profile field can hold (for example DATE for dateOfBirth).

Effect: from the next login on, every user with a missing required global field is stopped on the identity UI onboarding page before reaching the platform, whatever the platform's onboarding mode. Existing sessions continue. Nothing is required until you turn it on here.

Platform schemas below skip what is collected globally: the presets hide those fields, and a platform field for a globally collected profile field is merged into the global one on the onboarding page.

Platform schemas ​

The second part of the page manages each registered platform's own dynamic onboarding schema, including archived field definitions.

  1. Select the target Platform from the dropdown (keys come from the platform registry).
  2. Card loads GET /v1/platforms/{platformKey}/onboarding/fields (admin list includes active and archived definitions) and shows the current requirement version.
  3. Use presets, create a custom field, or open an existing definition to edit / archive / restore.

Only active fields are returned to end users on /v1/onboarding/{platformKey}/requirements and counted toward completion. Archived definitions stay visible here for operators.

Option A — Add standard fields (presets) ​

Use Add standard fields when you want the built-in English catalog (profile + common game/social customs).

  1. Tick the presets to add (grouped by category: Basic information, Location and preferences, Game integrations, Social accounts).
  2. Optionally tick Required next to each selected preset.
  3. Click Add selected fields.

Each selected preset becomes a POST /v1/platforms/{platformKey}/onboarding/fields. Already-present fieldKeys are hidden from the preset list.

Preset PROFILE_FIELD entries bind to canonical profile columns (firstName, dateOfBirth, …). Preset custom entries (steam64Id, riotId, social handles, …) are CUSTOM_FIELD values.

Option B — Create a custom field ​

Expand Create onboarding field, fill the form (same semantics as the editor below), then click Create field → POST /v1/platforms/{platformKey}/onboarding/fields.

Field editor reference ​

Opening an existing field (for example Middle name / middleName with status ACTIVE) shows the full definition editor. Field key is shown as a read-only identifier; it is set at create time and cannot change.

UI labelAPI propertyWhat it means / what to write
(title / key)fieldKeyStable machine id, e.g. middleName. Pattern ^[A-Za-z][A-Za-z0-9_]{1,63}$. Immutable after create. Used in APIs and in missingFields.
Status badgeactiveACTIVE = included in user requirements and completion checks. ARCHIVED = soft-deactivated; not shown to users, not required.
LabellabelEnd-user visible label (required). Max 200 chars. No HTML. Example: Middle name.
Field typefieldTypeControl + value type (see table below).
SourcesourceWhere the value is stored: Profile field (PROFILE_FIELD) or Custom field (CUSTOM_FIELD).
Profile fieldprofileFieldKeyRequired when source is Profile field; must be empty for Custom field. Canonical profile column to read/write.
DescriptiondescriptionOptional help / supporting text under the control. Max 1000 chars. No HTML.
PlaceholderplaceholderOptional empty-input hint. Max 300 chars. No HTML.
Sort ordersortOrderInteger render order (ascending). Example: 20. Ties fall back to creation time.
RequiredrequiredWhen checked, completion fails until the field has a non-empty valid value.
Options [JSON array]optionsChoices for SELECT / MULTI_SELECT only. Other types use [].
Validation [JSON object]validationOptional constraints enforced by the gateway on submit.
UI config [JSON object]uiConfigDisplay hints only (section grouping, width, help text). Never HTML or executable content.

Field types ​

fieldTypeUser controlSubmitted value
TEXTSingle-line textstring
TEXTAREAMultiline textstring
NUMBERNumber inputnumber
BOOLEANCheckboxboolean
DATEDate inputYYYY-MM-DD string
SELECTSingle selectone option value
MULTI_SELECTMulti select / checkbox groupstring array of option values
COUNTRYCountry controluppercase ISO 3166-1 alpha-2 (^[A-Z]{2}$)
PHONEPhone inputE.164-style international string (+ then digits)
EMAILEmail inputemail string
URLURL inputURL string

SELECT and MULTI_SELECT require a non-empty options array with unique values. Other types should keep options as [].

Source and profile field ​

Source in UIAPI sourceStorageprofileFieldKey
Profile fieldPROFILE_FIELDCanonical IESF profile column (shared across platforms)Required — pick one key below
Custom fieldCUSTOM_FIELDPlatform-scoped JSONB value for this definitionMust be empty / null

Allowed profileFieldKey values:

firstName, middleName, lastName, nickname, phoneNumber, dateOfBirth, gender, bio, nationalityCountryCode, secondaryNationalityCountryCode, residenceCountryCode, preferredLocale, timezone

Example: source Profile field, profile field middleName → user input updates the shared profile middleName column.

Prefer PROFILE_FIELD for identity data that should stay consistent everywhere. Use CUSTOM_FIELD for platform-specific data (federation id, game accounts, event answers, …).

Options [JSON array] ​

Shape (max 200 items). Each option needs a machine value and a human label:

json
[
  { "value": "male", "label": "Male" },
  { "value": "female", "label": "Female" },
  { "value": "other", "label": "Other" }
]

Rules:

  • Required and non-empty for SELECT / MULTI_SELECT
  • value strings must be unique
  • label is safe text (no HTML)
  • For non-select types, leave []

Validation [JSON object] ​

Allowed keys (all optional). Unknown keys are rejected. Empty object {} means no extra constraints beyond the field type.

KeyApplies toMeaning
minLengthTEXT, TEXTAREA (and other string types when set)Minimum string length (integer ≥ 0)
maxLengthsameMaximum string length (integer ≥ 1)
patternstring typesRegex string (max 500 chars) tested against the value
minNUMBERMinimum numeric value
maxNUMBERMaximum numeric value

Constraints: minLength must not exceed maxLength; min must not exceed max.

Typical text-length limit:

json
{
  "maxLength": 100
}

Stricter custom example:

json
{
  "minLength": 3,
  "maxLength": 50,
  "pattern": "^[A-Z0-9-]+$"
}

Built-in type rules still apply even when validation is {} (for example COUNTRY must be two uppercase letters; PHONE must match the international format; EMAIL / URL / DATE use their type validators).

UI config [JSON object] ​

Display hints for Account Center / platform UIs. Allowed keys only:

KeyValuesMeaning
sectionstring (max 100)Group heading, e.g. "Basic information"
widthfull | half | thirdSuggested grid width
helpTextstring (max 500)Extra supporting text (not HTML)
componentstring (max 50)Optional client hint for a known safe component name

Typical layout hint:

json
{
  "section": "Basic information",
  "width": "half"
}

Treat uiConfig as hints only. Clients must not interpret it as HTML, scripts, or remote URLs.

Edit, archive, and restore ​

ActionUI controlAPIEffect
Save changesSave fieldPATCH /v1/platforms/{platformKey}/onboarding/fields/{fieldKey}Updates mutable properties; bumps requirement_version
ArchiveArchiveDELETE …/fields/{fieldKey}Sets active=false (soft deactivate). Historical user values remain. Field drops out of requirements / completion.
RestoreSave with active / un-archive control (or PATCH active: true)PATCH with "active": trueDefinition returns to the live schema; bumps version again

Archived definitions remain listed on this admin page so operators can inspect or restore them. They are not returned on the user-facing requirements endpoint.

Effect on users ​

Every create / update / archive / restore increments platforms.requirement_version and moves previously COMPLETE memberships back to IN_PROGRESS. The next login or status check re-evaluates missing fields against the new schema. No SQL migration is required.

  1. Register the platform key and save the one-time BFF key of every pair (/admin/platforms); generate the backend key if a platform API introspects.
  2. Configure onboarding fields for that key (/admin/onboarding).
  3. Give the platform team: platformKey, identity environment, redirect pairs, onboarding mode, and the keys (one per BFF deployment, plus the backend key).
  4. Platform implements start → callback → exchange (Platform integration).