Skip to content
bitzorcas
中EN

Reference

Identity frontend

Complete usage and implementation reference for BitzOrcas Web Identity: encrypted credential sign-in, CAPTCHA, MFA, passwords, admissions, authorization, organizations, application credentials, and tenant governance.

Last updated

Identity is the first complete Platform frontend vertical slice. It is not an isolated sign-in screen. It covers public entry points, authentication state, account lifecycle, and administrative security operations. Pages consume Design System 1.2 and @bitz/platform-sdk; they do not store refresh tokens, duplicate backend DTOs, or call fetch directly.

1. Page entry points

Public routes

RoutePurpose
/loginCredential sign-in; follows server outcomes for CAPTCHA, MFA, or password change
/forgot-passwordRequests a reset with an enumeration-safe result
/reset-password?userId=&token=Sets a new password from a protected link
/accept-invitation?token=Accepts a directed or open invitation and submits admission data
/activate?token=Activates an approved account and sets its first password
/verify-email?userId=&token=Confirms an email address
/verify-phone?userId=&token=Confirms a phone number
/external-login/completeRestores the HttpOnly-cookie session after an external callback
/session-expiredProvides an explicit recovery path after session invalidation

Authenticated routes

RoutePurpose
/change-passwordVoluntary password change or completion of a forced change
/settings/securityMFA, recovery codes, passkeys, OTP, devices, sessions, and personal login history
/usersUser search, creation, profile, status, organization, and role operations
/identity/accessInvitations, admissions, role permissions, ABAC, features, and tenant login audit
/identity/organizationOrganization tree and hierarchy management
/identity/applicationsAPI keys, HMAC clients, and OAuth applications
/host/tenantsTenant creation, provisioning, suspension, recovery, and deactivation (Host surface)
/integrationsTenant integrations including external sign-in, SCIM, Webhooks, notifications, and AI

2. Sign-in state machine

captcharefreshmfapassword-change-requiredauthenticated

Username + password

GET /api/auth/cipher-key

Encrypt with Web Crypto RSA-OAEP

POST /api/auth/login ciphertext

LoginOutcome

Render server CAPTCHA

POST /api/auth/captcha/refresh

TOTP / recovery code / passkey

POST /api/mfa/verify or FIDO2

/change-password

GET /api/auth/me

Return to original route

The page does not infer a branch from an empty token or an HTTP status. AuthSession.handleLoginSuccess() reduces the server response to a stable discriminated union:

// Pages match on kind; protocol details remain inside the SDK.
type LoginOutcome =
| { kind: "authenticated" }
| { kind: "captcha"; challengeId: string; renderData: string }
| { kind: "mfa"; mfaToken: string }
| { kind: "mfa-enrollment-required" }
| { kind: "password-change-required" };

Graphical CAPTCHA is risk-triggered, not a mandatory step in every sign-in. Repeated failures or anomalous network and device signals can require it. Refresh submits only the account and previous challenge identifier; it does not resend the password. Refresh invalidates the old challenge. A CAPTCHA error or another failed sign-in also replaces the image, clears the input, and restores focus.

Rendering supports SVG, PNG, JPEG, and GIF Base64 plus data/blob URLs. MFA verification uses a short-lived MfaToken as proof that the password stage completed; it does not send a Bearer token.

Sign-in media

The legal-counsel studio poster is the first-render and failure fallback. Muted looping video loads only on desktop when reduced-motion and data-saver preferences are both off. Small screens and users who prefer reduced motion receive the static poster. The video is excluded from PWA precaching.

Appearance settings

Public Identity pages provide Light, Dark, System, Navy, Amber, Burgundy, and Jade themes. Sign-in, CAPTCHA, MFA, invitation, and recovery pages remain at Comfortable density, so they do not expose an inactive density switch. The authenticated global header adds Dense, Compact, and Comfortable.

Mode, Brand, and Density change presentation only. localStorage stores these non-sensitive visual preferences, never credentials, account context, workspace facts, or permissions. If persistence is blocked, changes remain effective for the current page session.

3. Session and credential rules

  • The access token exists only in an AuthSession memory field.
  • The refresh token exists only in the backend-issued HttpOnly cookie.
  • Initial load refreshes first, then reads /api/auth/me; the state remains bootstrapping until both complete.
  • Concurrent 401 responses share one refresh promise; each original request retries only once.
  • sessionRevision prevents an old refresh from overwriting a later sign-in, MFA completion, or logout.
  • Logout first attempts server-side revocation; local memory is cleared even when the request fails.

One-time-link token and userId values are captured during bootstrap and then removed from the address bar with replace navigation. Browser history, resource referrers, and later screenshots do not keep carrying them.

4. MFA and Account Security

Two-phase enrollment

  1. POST /api/mfa/setup returns the QR code and manual key while storing only a short-lived pending secret.
  2. The user scans the QR code and enters the first six-digit TOTP.
  3. POST /api/mfa/setup/confirm validates the code.
  4. The server enables MFA only after confirmation succeeds.
  5. Disabling MFA requires a current TOTP.

Recovery codes

  • The status endpoint returns only the remaining count, never historical plaintext.
  • Regeneration requires a current TOTP and immediately invalidates every old code.
  • New codes appear only in that response. The page warns the user to save them and does not persist them in browser storage.
  • Sign-in accepts one unused 16-character recovery code and consumes it after success.

Passkeys

  • Account Security registers a platform authenticator or security key through FIDO2 register begin/complete.
  • Sign-in obtains a challenge from login begin and calls navigator.credentials.get().
  • Unsupported browsers and user cancellation fall back explicitly to TOTP or a recovery code.
  • Biometric data never reaches the application; the server validates the public-key credential, challenge, RP, and origin.

Trusted devices, sessions, and audit

  • Trusting the current device requires TOTP; the server records ownership with a 30-day expiry.
  • Users can revoke trust, remove a device, revoke one session, or revoke every other session.
  • Personal login history shows result, method, IP, device, and failure reason.
  • Tenant administrators can query per-user tenant login audit in Access Control.

5. Passwords and contact verification

Password pages read the deployed policy from GET /api/password/policy:

// Length and character requirements come from the server policy.
// This response carries rules only; it never contains a password or secret.
type PasswordPolicyResponse = {
requiredLength: number;
maximumLength: number;
requiredUniqueChars: number;
requireDigit: boolean;
requireLowercase: boolean;
requireUppercase: boolean;
requireNonAlphanumeric: boolean;
};

Activation, reset, and password change use the same policy hook and rules component. If the endpoint is temporarily unavailable, the UI uses a conservative fallback, but the server always performs the final validation. Password history, current-password checks, and tenant policy cannot be reproduced reliably in the browser.

Notification behavior is explicit:

  • Password-reset requests return the same public result to prevent account enumeration.
  • Email verification sends a one-time link.
  • Phone verification and SMS OTP send a six-digit code.
  • A missing email or SMS provider causes an explicit server failure; API acceptance is not delivery evidence.

6. Invitations, admissions, and users

/identity/access separates invitations, admissions, authorization policy, and login audit:

  • Invitations can target an email or use an open link and can constrain domain, role, organization, office, expiry, and maximum uses.
  • Accepting an invitation creates a PendingReview admission, not an immediately active user.
  • Approval creates a pending-activation user and sends activation instructions.
  • Reject, revoke, and other dangerous actions require confirmation.

/users provides search, server pagination, creation, profile editing, organization membership, role assignment, lock, unlock, enable, disable, and delete. Profile updates and role grants use separate APIs and permission boundaries; authorization changes are not hidden inside a profile form.

7. Roles, ABAC, and features

  • Roles collect permissions; users receive roles rather than loose permissions assembled in the user form.
  • Permission trees and role grants come from the server.
  • ABAC rules submit stable scope, action, condition, decision, and priority values.
  • Feature management shows platform defaults, tenant overrides, and effective values.
  • Frontend gates improve visibility and interaction only; backend Authorization remains the security authority.

8. Organizations, application credentials, tenants, and integrations

Organization management creates, edits, moves, and deletes root and child nodes. The page removes obviously invalid destinations. The server makes the final cycle check and protects nodes that still have members or children.

Application Credentials manages:

  • API keys with minimum scopes, rotation, and revocation;
  • HMAC request-signing clients with scopes and secret rotation;
  • OAuth applications with redirect URIs, scopes, PKCE, and client secrets.

Every secret is shown once in a create or rotation response; list operations never return plaintext.

Tenant governance follows the backend state machine for creation, provisioning, suspension, recovery, and deactivation. The page does not predict illegal transitions. Each operation includes a reason and waits for the server decision.

The External Sign-in sheet at /integrations manages tenant Azure AD, generic OAuth2, LDAP, and WeChat Mini Program configurations. Lists reveal only configured secret-key names. Save operations can replace or explicitly clear credentials, deletes carry an optimistic Version, and connection tests use the saved configuration. The entry requires identity.externallogin.manage; protocol adapters remain statically loaded by the Host. See Identity configuration and integrations for fields, readiness states, and runtime invalidation.

9. Page implementation rules

Pages consume the shared API only
// The shared result is mapped to a stable user-facing error before state changes.
// A failed request leaves the last successful session list untouched.
const { api } = usePlatform();
const result = await api.listSessions();
if (!result.ok) {
setMessage(friendlyIdentityError(result.error, t.tRaw));
return;
}
setSessions(result.data);
  • HTTP goes through usePlatform().api; sign-in uses provider-level login, verifyMfa, and logout.
  • DTOs come from @bitz/platform-sdk and the generated OpenAPI client.
  • Primitives come from @bitz/components, composites from @bitz/widgets; deep imports are prohibited.
  • IdentityField connects labels, hints, errors, and ARIA attributes.
  • Dangerous actions use ConfirmAction; in-flight controls are disabled and show a Spinner.
  • Color, type, spacing, radius, shadow, and navigation foreground consume Design System 1.2 tokens.

10. Deployment acceptance

  1. Configure a valid Runtime License and start the application against the real API Host.
  2. Set Frontend:BaseUrl to the public HTTPS origin.
  3. Configure real email, SMS, and external-identity adapters; require Ready and a successful real connection test in Integration Center.
  4. Match refresh-cookie Secure, SameSite, and Domain settings to the deployment topology.
  5. Complete setup → confirm → logout → MFA sign-in with a real authenticator.
  6. Register, use, and delete a passkey with a platform keychain or security key.
  7. Verify that a recovery code is single-use and revoking trust restores full MFA.
  8. Recheck pages, tabs, buttons, and backend 403 results with a least-privilege account.
  9. Verify that users, roles, devices, sessions, organizations, audit, and credentials cannot cross tenants.

11. Regression commands

Terminal window
# backend contracts and application tests
scripts/build/export-openapi.sh
dotnet test tests/BitzOrcas.Application.Tests/BitzOrcas.Application.Tests.csproj \
--filter 'FullyQualifiedName~Identity|FullyQualifiedName~Authorization'
# frontend
cd frontend
yarn workspace @bitz/platform-sdk generate-client
yarn workspace @bitz/platform-sdk test
yarn workspace @bitz/materials test
yarn lint
yarn typecheck
yarn build
# Identity design boundary: all three commands should produce no output
rg -n '#[0-9A-Fa-f]{3,8}|rgb\\(|hsl\\(|oklch\\(' \
apps/app/src/pages/identity apps/app/src/pages/login
rg -n -- '--ref-|--login-' apps/app/src/pages/identity apps/app/src/pages/login
rg -n '\\b(fetch|axios|XMLHttpRequest)\\b|localStorage|sessionStorage' \
apps/app/src/pages/identity apps/app/src/pages/login

Back to Frontend · Platform SDK · Design System 1.2

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%