AUTH4D-21 project onboarding and application configuration screens

Console screens in apps/console/src/features/projects/ let developers create projects, register applications and copy integration settings. They add no API routes: every call goes through the console BFF to the AUTH4D-18 management routes, and the API remains the authority for validation and roles. The fixed AUTH4D-20 route table mounts them through the placeholders in features/{project-create,applications,sign-in-methods,project-settings}.

Console route Management calls (via /api/management/…)
/projects/new POST /tenants (displayName, idempotencyKey)
/projects/{id}/applications GET /tenants/{id}, GET /tenants/{id}/clients
/projects/{id}/applications?new=1 POST /tenants/{id}/clients (with idempotencyKey)
/projects/{id}/applications?app={clientId} GET, PATCH, DELETE /tenants/{id}/clients/{cid}
/projects/{id}/sign-in-methods GET, PATCH /tenants/{id} (signup, guest, email, Discord)
/projects/{id}/settings GET, PATCH /tenants/{id} (name, scope ceiling)

Behavior

  • Onboarding. A developer with no projects sees a short getting-started outline. After creation the console reloads the project list and opens the applications screen. Create requests carry a random idempotency key that is reused while the submitted values are unchanged, so a retried request cannot create a duplicate.
  • Applications. Only browser and native (game, device authorization) types are offered. Browser forms edit redirect URIs and allowed origins (one per line); native forms send neither. Scopes are chosen from the project’s allowedScopes. Disabling uses DELETE with {} after a confirmation dialog; enabling uses PATCH {"enabled":true}. Forms never send client secrets, grant types, audiences or authentication methods.
  • Field errors. The shared API client keeps only the error code, so writes use a per-call client that also reads error.message and error.details[].field. Errors are shown beside the matching input (redirectUris, allowedOrigins, allowedScopes, displayName, providers.discord.clientId, providers.discord.clientSecret), and any others in the form summary. A 401 is passed to the shared client, which marks the console session as expired.
  • Discord credentials. The client secret is a write-only password input. It starts empty, is sent only when the developer types a value, and is cleared after a save. The screen only shows clientSecretConfigured and clientSecretUpdatedAt.
  • Roles. The role comes from GET /tenants/{id} (owner, admin, viewer; anything else is treated as viewer). Owners edit everything. Admins edit applications. Viewers see disabled controls, no save, create or disable actions, and no secret input. The API still enforces every write, and its 403 insufficient_role is shown if a role changes while a page is open.
  • Integration values. Each application shows copyable issuer ({AUTH_ORIGIN}/t/{tenantId}), client ID, audience (the client ID, which is the aud of its tokens), and either the callback URL (browser) or the device authorization endpoint (native), plus framework-neutral snippets: OIDC settings and @auth4/sdk-browser for browser apps, device authorization and token polling requests for games, and @auth4/sdk-server verification. No client secret is shown or invented. The console derives AUTH_ORIGIN from its own host (app.{domain} → auth.{domain}, loopback → port 8787), or from the build-time variable VITE_AUTH4_AUTH_ORIGIN.
  • Nothing is written to browser storage. Copy uses the Clipboard API and falls back to selecting the text.

Tests

tests/e2e/auth4d-21.projects.spec.ts has 10 Playwright tests that run against a stateful mock of the BFF that matches the AUTH4D-18 error format. They cover onboarding, browser and native registration, backend redirect, origin and scope errors, editing and disabling an application, sign-in method changes, write-only Discord credential replacement, settings that persist after reload, copyable values, viewer and admin controls, and a role change while a page is open. They use their own port (5186) and output directories:

pnpm exec playwright test -c tests/e2e/auth4d-21.playwright.config.ts

Source: docs/api-spec/auth4d-21.md