Files
WRNexusJSDoc/app/pages/packages/auth.wrn
T
ClintchizandClaude Opus 5.5 b536b57447 docs: update portal for WRNexusJS 0.8.72
- Bump every @wrnexus/* dependency to its latest release (ui 0.8.88,
  styles 0.8.26, cli 0.8.72, core 0.8.16, i18n 0.8.12, ...) and refresh
  bun.lock and package-lock.json. graphql/native 0.8.8 were republished,
  so their stale lockfile integrity entries were re-resolved.
- wrnexus.config.ts: drop `functions` and `compatibility`, both removed
  from the framework.
- Regenerate package, portal and discovery docs from the installed
  packages, including the new 0.8.72 release page.
- Package pages now install each package's own released version
  (ui 0.8.88, core 0.8.16) instead of stamping the CLI version on all.
- llms.txt / llms-full.txt: the generator kept every earlier run's CLI
  reference and appended another; it now replaces it, so the guide holds
  one current reference and no longer advertises the removed
  `wrnexus compatibility` command.
- docs.test.ts: compileWireFile was renamed compileWrnFile; tests follow
  the per-package install versions and the removed command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:46:32 +05:30

426 lines
35 KiB
Plaintext

page wrnexusauth {
seo {
title = "@wrnexus/auth"
description = "Authentication routes, sessions, forms, guards, and account flows."
}
view {
<div class="docs-shell">
<a href="#main" class="skip-link">Skip to content</a>
<header class="topbar">
<a class="brand" href="/"><span>W</span> WRNexusJS</a>
<nav aria-label="Primary"><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a></nav>
<div class="topbar-actions"><a class="preview-pill" href="/access">Private preview · v0.8.72</a><button data-wire-theme-toggle class="theme-button" aria-label="Toggle color theme" title="Toggle color theme">◐</button></div>
</header>
<div class="mobile-doc-nav"><details><summary>Browse documentation</summary><nav><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a><a href="/tutorial">Tutorial</a><a href="/guides/project-structure">Guides</a><a href="/examples">Examples</a><a href="/search">Search</a></nav></details></div>
<main id="main" class="portal-main docs-layout docs-layout--navigation"><aside class="docs-section-menu" aria-label="Documentation sections"><nav>
<section><strong>Get started</strong><a href="/getting-started">Quick start</a><a href="/tutorial">Tutorial</a><a href="/guides/full-stack-auth-demo">Auth dashboard demo</a><a href="/guides/configuration-and-profiles">Configuration</a></section>
<section><strong>Build</strong><a href="/guides/pages-and-components">Pages and components</a><a href="/guides/routing">Routing</a><a href="/guides/server-data">Server data</a><a href="/guides/forms-and-validation">Forms and validation</a><a href="/guides/database">Database</a></section>
<section><strong>Auth and security</strong><a href="/guides/authentication">Authentication</a><a href="/guides/authorization">Authorization</a><a href="/guides/security">Application security</a><a href="/security">Security policy</a></section>
<section><strong>Reference</strong><a href="/packages">Packages overview</a><a href="/packages/cli">CLI</a><a href="/language">.wrn language</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/examples">Examples</a></section>
<section class="package-menu"><strong>Packages</strong><a href="/packages/ai">@wrnexus/ai</a><a href="/packages/auth">@wrnexus/auth</a><a href="/packages/authz">@wrnexus/authz</a><a href="/packages/benchmark">@wrnexus/benchmark</a><a href="/packages/cache">@wrnexus/cache</a><a href="/packages/captcha">@wrnexus/captcha</a><a href="/packages/cli">@wrnexus/cli</a><a href="/packages/compiler">@wrnexus/compiler</a><a href="/packages/content">@wrnexus/content</a><a href="/packages/core">@wrnexus/core</a><a href="/packages/csr">@wrnexus/csr</a><a href="/packages/db">@wrnexus/db</a><a href="/packages/dev-server">@wrnexus/dev-server</a><a href="/packages/dev-toolbar">@wrnexus/dev-toolbar</a><a href="/packages/encryption">@wrnexus/encryption</a><a href="/packages/graphql">@wrnexus/graphql</a><a href="/packages/helpers">@wrnexus/helpers</a><a href="/packages/i18n">@wrnexus/i18n</a><a href="/packages/identity">@wrnexus/identity</a><a href="/packages/image">@wrnexus/image</a><a href="/packages/jwt">@wrnexus/jwt</a><a href="/packages/language-server">@wrnexus/language-server</a><a href="/packages/mcp">@wrnexus/mcp</a><a href="/packages/mobile">@wrnexus/mobile</a><a href="/packages/native">@wrnexus/native</a><a href="/packages/oauth">@wrnexus/oauth</a><a href="/packages/observability">@wrnexus/observability</a><a href="/packages/playground">@wrnexus/playground</a><a href="/packages/plugin">@wrnexus/plugin</a><a href="/packages/pubsub">@wrnexus/pubsub</a><a href="/packages/pwa">@wrnexus/pwa</a><a href="/packages/queue">@wrnexus/queue</a><a href="/packages/reactive">@wrnexus/reactive</a><a href="/packages/realtime">@wrnexus/realtime</a><a href="/packages/router">@wrnexus/router</a><a href="/packages/security">@wrnexus/security</a><a href="/packages/ssr">@wrnexus/ssr</a><a href="/packages/store">@wrnexus/store</a><a href="/packages/styles">@wrnexus/styles</a><a href="/packages/syntax">@wrnexus/syntax</a><a href="/packages/test">@wrnexus/test</a><a href="/packages/tracking">@wrnexus/tracking</a><a href="/packages/typecheck">@wrnexus/typecheck</a><a href="/packages/ui">@wrnexus/ui</a><a href="/packages/uploader">@wrnexus/uploader</a><a href="/packages/validation">@wrnexus/validation</a></section>
</nav></aside><div class="docs-reading-column">
<article class="documentation prose standalone package-document"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><a href="/packages">Packages</a><span>/</span><span aria-current="page">@wrnexus/auth</span></nav><section class="doc-intro"><span class="eyebrow">Security · Package reference</span><h1>@wrnexus/auth</h1><p>Authentication routes, sessions, forms, guards, and account flows.</p><div class="doc-meta"><span>v0.8.33</span><span>Private registry</span><span>Security</span></div><section id="access" class="access-callout"><h2>Install the package</h2><p>After WorkRoot approves private registry access, install the package:</p><pre><code>bun add @wrnexus/auth@0.8.33</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide"><h4 id="new-browser-verification-and-device-trust">New-browser verification and device trust</h4>
<p>Enable <code>requireTrustedDeviceVerification: true</code> to require a verified email or SMS challenge before an untrusted browser receives a sign-in session. The HTTP handlers use a host-only HttpOnly random cookie, ignoring posted fingerprints. Direct engine callers must supply a trusted server-side browser fingerprint. <code>trustSignupDevice: true</code> grants the registration browser one-time trust after required account verification, at its first successful sign-in.</p>
<p>Use <code>trustedDeviceTtlMs: 30 * 86400_000</code> for 30-day trust. Ordinary logins do not renew it. The verification form offers explicit trust consent; expiry/revocation requires a new email/SMS challenge. Successful login alerts use both verified contact channels when configured. Delivery still requires an application adapter.</p>
<h4 id="signup-business-logic-and-verification-only-sessions">Signup business logic and verification-only sessions</h4>
<pre data-language="ts"><code>const auth = createAuthEngine(&#123;
store: () =&gt; new SqlAuthStore(getDb()),
secret: process.env.AUTH_SECRET!,
requireVerifiedEmail: true,
onSignUp(ctx, user) &#123;
// Application business logic can run here after successful registration.
return &#123; verificationSession: true, redirectTo: &quot;/verify-email&quot; &#125;;
&#125;,
delivery: &#123;
async send(message) &#123;
// message.channel, template, destination, user, expiresAt
// Verification uses message.token and message.url; OTP flows use message.code.
// Render your branded content here before passing it to your provider.
&#125;,
&#125;,
&#125;);</code></pre>
<p><code>onSuccessfulSignUp</code> remains supported; configure only one signup hook. Hooks run from the HTTP registration handler and may return an action or a custom Response. The request origin (or configured <code>auth.baseUrl</code>) supplies signup link URLs; a client-supplied <code>baseUrl</code> is never trusted. Direct <code>engine.register</code> callers may provide a trusted <code>baseUrl</code> explicitly.</p>
<p>The verification cookie is HttpOnly, SameSite=Lax, Secure on HTTPS, and host-only. Its opaque token is stored hashed in the auth token store, separate from login sessions; it cannot bypass email verification, MFA, or account policy. Use <code>getVerificationUser(ctx, auth)</code> to guard your verification page and <code>clearVerificationSession(ctx, auth)</code> after verification. Use <code>startVerificationSession(ctx, auth, user.id)</code> only after credential validation when an unverified user signs in again. SQL-backed sessions survive server reloads; memory stores remain development/test-only. No email or SMS provider is configured automatically.</p>
<p>Framework-native authentication, identity, account-security, and session management for WRNexusJS.</p>
<h3 id="capabilities">Capabilities</h3>
<ul>
<li>Password registration, login, recovery, reset, and authenticated password changes</li>
<li>Email, phone, and username identities with verification and generic resend responses</li>
<li>Magic links and passwordless email/SMS OTP login</li>
<li>MFA transactions using verified email OTP, verified SMS OTP, TOTP, or recovery codes</li>
<li>RFC 6238 TOTP with counter replay protection</li>
<li>One-use recovery codes; regeneration invalidates previous unused codes</li>
<li>Passkey/WebAuthn registration and strong passwordless sign-in through a provider contract</li>
<li>OAuth account linking and provider sign-in</li>
<li>Invitations, session rotation, idle and absolute expiry, revocation, and trusted devices</li>
<li>Deny-by-default audited support impersonation</li>
<li>Adaptive risk scoring, CAPTCHA escalation, temporary lockout, and optional login alerts</li>
<li>Memory and SQL stores</li>
<li>Optional encryption-keyring protection for TOTP and OAuth secrets</li>
<li>Automatic API routes, middleware, browser schemas, components, runtime, migrations, and DevToolbar checks</li>
</ul>
<p>Passkeys are a strong sign-in method. They are not currently exposed as a selectable second step in <code>TwoFactorChallenge</code>; the implemented MFA methods are email OTP, SMS OTP, TOTP, and recovery codes.</p>
<h3 id="install">Install</h3>
<pre data-language="bash"><code>bun add @wrnexus/auth</code></pre>
<p>WRNexusJS discovers the package automatically. Do not copy package components, client scripts, schemas, or standard <code>/api/auth/*</code> route files into the application.</p>
<h3 id="default-configuration">Default configuration</h3>
<p>Create the engine:</p>
<pre data-language="ts"><code>// app/lib/auth.ts
import &#123; createAuthEngine, MemoryAuthStore &#125; from &quot;@wrnexus/auth&quot;;
export const auth = createAuthEngine(&#123;
store: new MemoryAuthStore(),
secret: process.env.AUTH_SECRET!,
issuer: &quot;My application&quot;,
onSignedIn(ctx, returnTo) &#123;
const safe = returnTo?.startsWith(&quot;/&quot;) &amp;&amp; !returnTo.startsWith(&quot;//&quot;) ? returnTo : &quot;/account&quot;;
return Response.redirect(new URL(safe, ctx.url), 303);
&#125;,
onSignedOut(ctx) &#123;
return Response.redirect(new URL(&quot;/sign-in&quot;, ctx.url), 303);
&#125;,
onSuccessfulSignUp() &#123;
return &#123;
autoSignIn: true,
redirectTo: &quot;/account&quot;,
&#125;;
&#125;,
delivery: &#123;
async send(message) &#123;
// Queue email/SMS through your provider. Never log message.code or message.token.
&#125;,
&#125;,
&#125;);</code></pre>
<p>Authentication behavior belongs in this engine definition: delivery, token URL mapping, successful sign-in/sign-out responses, password policy, risk thresholds, MFA, passkeys, and auditing can all be configured in one server-only location. The older <code>config.auth.onSignedIn</code> and <code>config.auth.onSignedOut</code> fields remain supported as compatibility overrides, but new applications should configure these hooks on <code>createAuthEngine</code>.</p>
<h4 id="successful-signup-behavior">Successful signup behavior</h4>
<p>Without <code>onSuccessfulSignUp</code>, a successful package registration redirects to <code>/sign-in</code>.</p>
<p>To sign in immediately after registration:</p>
<pre data-language="ts"><code>onSuccessfulSignUp(ctx, user) &#123;
return &#123;
autoSignIn: true,
redirectTo: &quot;/account&quot;,
&#125;;
&#125;</code></pre>
<p>Automatic sign-in runs the normal login policy. It does not bypass required email or phone verification, CAPTCHA, MFA, account status, or risk checks. The hook may also return a <code>Response</code> for a completely custom HTTP result, or return <code>&#123; redirectTo: &quot;/welcome&quot; &#125;</code> to redirect without creating a session.</p>
<p>Register it through application configuration:</p>
<pre data-language="ts"><code>// wrnexus.config.ts
import type &#123; AuthConfig &#125; from &quot;@wrnexus/auth&quot;;
import type &#123; AppConfig &#125; from &quot;@wrnexus/styles&quot;;
import &#123; auth &#125; from &quot;./app/lib/auth.ts&quot;;
const config = &#123;
auth: &#123;
engine: auth,
routes: true,
middleware: true,
migrations: false,
&#125;,
&#125; satisfies AppConfig &amp; &#123; auth: AuthConfig &#125;;
export default config;</code></pre>
<p>That configuration automatically activates package routes, auth-session middleware, components, browser validation schemas, and the auth client runtime. <code>setDefaultAuthEngine()</code> remains available only for advanced manual integrations and tests.</p>
<h3 id="sql-production-configuration">SQL production configuration</h3>
<pre data-language="ts"><code>import &#123; createAuthEngine, SqlAuthStore &#125; from &quot;@wrnexus/auth&quot;;
import &#123; getDb &#125; from &quot;@wrnexus/db&quot;;
export const auth = createAuthEngine(&#123;
store: new SqlAuthStore(getDb()),
secret: process.env.AUTH_SECRET!,
&#125;);</code></pre>
<pre data-language="ts"><code>export default &#123;
db: &#123;
// Application database configuration.
&#125;,
auth: &#123;
engine: auth,
routes: true,
middleware: true,
migrations: true,
&#125;,
&#125;;</code></pre>
<p>The package contributes both ordered migrations:</p>
<pre data-language="text"><code>001_auth.sql
002_auth_otp_purpose.sql</code></pre>
<p>Migrations are enabled automatically only when <code>auth.engine</code> and a default <code>config.db</code> are present. Set <code>auth.migrations</code> explicitly when an application needs different behavior.</p>
<h3 id="delivered-action-urls">Delivered action URLs</h3>
<p>By default, the engine builds links from the supplied <code>baseUrl</code> and token purpose. Applications can map those links to their own page structure without replacing package APIs:</p>
<pre data-language="ts"><code>const auth = createAuthEngine(&#123;
store: new SqlAuthStore(getDb()),
secret: process.env.AUTH_SECRET!,
tokenUrl(&#123; purpose, token, baseUrl &#125;) &#123;
if (!baseUrl) return undefined;
const paths = &#123;
&quot;verify-email&quot;: `/verify-email?token=$&#123;encodeURIComponent(token)&#125;`,
&quot;verify-phone&quot;: `/verify-phone?token=$&#123;encodeURIComponent(token)&#125;`,
&quot;password-reset&quot;: `/recover/reset?token=$&#123;encodeURIComponent(token)&#125;`,
&quot;magic-link&quot;: `/magic-link?token=$&#123;encodeURIComponent(token)&#125;`,
invite: `/invitation?token=$&#123;encodeURIComponent(token)&#125;`,
&#125;;
const path = paths[purpose as keyof typeof paths];
return path ? new URL(path, baseUrl).toString() : undefined;
&#125;,
&#125;);</code></pre>
<p>Returning <code>undefined</code> intentionally omits the URL while still delivering the raw token. The callback runs only in trusted server code.</p>
<h3 id="built-in-validation">Built-in validation</h3>
<p>Every packaged auth form has a built-in <code>@wrnexus/validation</code> schema. The same resolved schema is used by the browser and the package API handler.</p>
<p>Default use requires no <code>app/schemas</code> files:</p>
<pre data-language="wrn"><code>&lt;SignUp /&gt;
&lt;SignIn /&gt;
&lt;ForgotPassword /&gt;
&lt;ResetPassword token='&#123;token&#125;' /&gt;
&lt;TwoFactorChallenge /&gt;</code></pre>
<p>To customize one schema, extend the package default and register only that override:</p>
<pre data-language="ts"><code>// app/schemas/custom-password-request.ts
import &#123; authSchemas &#125; from &quot;@wrnexus/auth&quot;;
import &#123; v &#125; from &quot;@wrnexus/validation&quot;;
export default authSchemas.passwordResetRequest.extend(&#123;
identifier: v
.string()
.trim()
.required(&quot;Enter your registered email address&quot;)
.email(&quot;Enter a valid registered email address&quot;),
&#125;);</code></pre>
<pre data-language="ts"><code>import customPasswordRequest from &quot;./app/schemas/custom-password-request.ts&quot;;
export default &#123;
auth: &#123;
engine: auth,
schemas: &#123;
passwordResetRequest: customPasswordRequest,
&#125;,
&#125;,
&#125;;</code></pre>
<p><code>&lt;ForgotPassword /&gt;</code> can keep its default <code>schema=&quot;auth-password-request&quot;</code>. The plugin automatically publishes the overridden browser descriptor under that same built-in schema ID. All other forms continue using package defaults.</p>
<h3 id="route-controls">Route controls</h3>
<p>Use a boolean to enable or disable all package routes:</p>
<pre data-language="ts"><code>auth: &#123;
engine: auth,
routes: true,
&#125;</code></pre>
<p>Or control feature groups:</p>
<pre data-language="ts"><code>routes: &#123;
enabled: true,
registration: true,
login: true,
verification: true,
password: true,
invitations: true,
magicLink: true,
otp: true,
mfa: true,
sessions: true,
impersonation: false,
passkeys: true,
&#125;</code></pre>
<p>Application routes have normal framework precedence. Disable a package group only when the application intentionally owns every endpoint in that group; no <code>excludeRoutes</code> list is required.</p>
<h3 id="package-endpoints">Package endpoints</h3>
<pre data-language="text"><code>POST /api/auth/register
POST /api/auth/login
POST /api/auth/logout
POST /api/auth/verification/request
GET|POST /api/auth/verify/email
POST /api/auth/verify/phone
POST /api/auth/password/request
POST /api/auth/password/reset
POST /api/auth/password/change
POST /api/auth/invitations/accept
POST /api/auth/magic-link/request
GET|POST /api/auth/magic-link
POST /api/auth/otp/login/request
POST /api/auth/otp/login/complete
POST /api/auth/otp
POST /api/auth/otp/verify
POST /api/auth/totp/setup
POST /api/auth/totp/confirm
POST /api/auth/totp/disable
POST /api/auth/recovery-codes
POST /api/auth/mfa/otp
POST /api/auth/mfa/complete
GET /api/auth/sessions
POST /api/auth/sessions/revoke
POST /api/auth/impersonation/start
POST /api/auth/impersonation/stop
POST /api/auth/passkeys/register/options
POST /api/auth/passkeys/register/verify
POST /api/auth/passkeys/login/options
POST /api/auth/passkeys/login/verify</code></pre>
<p>Each URL uses a route-specific module, so rewritten framework request URLs cannot make the handler fall through to a shared-dispatcher <code>404</code>.</p>
<p>Unsafe package routes validate the framework CSRF token by default. Set <code>auth.csrf: false</code> only when an external API gateway provides an equivalent protection model.</p>
<h3 id="components">Components</h3>
<pre data-language="wrn"><code>&lt;SignIn /&gt;
&lt;SignUp /&gt;
&lt;ForgotPassword /&gt;
&lt;ResetPassword token='&#123;token&#125;' /&gt;
&lt;OtpSignIn method=&quot;email-otp&quot; /&gt;
&lt;MagicLinkSignIn /&gt;
&lt;PasskeyButton mode=&quot;authenticate&quot; /&gt;
&lt;TwoFactorChallenge mfaToken='&#123;mfaToken&#125;' challengeId='&#123;challengeId&#125;' /&gt;
&lt;AuthenticatorSetup credentialId='&#123;credentialId&#125;' secret='&#123;secret&#125;' uri='&#123;uri&#125;' /&gt;
&lt;RecoveryCodes codes='&#123;codes&#125;' /&gt;
&lt;DeviceSessions sessions='&#123;sessions&#125;' currentSessionId='&#123;currentSessionId&#125;' /&gt;
&lt;VerifyEmail token='&#123;token&#125;' identifier='&#123;identifier&#125;' /&gt;
&lt;VerifyPhone token='&#123;token&#125;' identifier='&#123;identifier&#125;' /&gt;
&lt;InvitationAccept token='&#123;token&#125;' /&gt;
&lt;ImpersonationBanner targetName='&#123;targetName&#125;' /&gt;
&lt;AccountStatus status='&#123;account.status&#125;' /&gt;</code></pre>
<p><code>identifier</code> is optional on verification components. Supply it when an unauthenticated verification page should support resending a token. The response remains generic whether the account exists or not.</p>
<h3 id="captcha-and-risk">CAPTCHA and risk</h3>
<p>The HTTP handlers never trust a browser <code>captchaVerified</code> field. CAPTCHA completion is accepted only from server-populated <code>ctx.locals.captcha.success</code> or <code>ctx.locals.captchaVerified === true</code>.</p>
<p>Rate limiting remains an application or gateway responsibility. Apply it to registration, login, reset, magic-link, OTP, verification, passkey, invitation, and impersonation endpoints.</p>
<h3 id="mfa">MFA</h3>
<p>1. Password, OAuth, magic-link, or OTP login may return <code>code: &quot;mfa-required&quot;</code> with a short-lived <code>mfaToken</code>. 2. The response lists only methods actually available to that user. 3. Email/SMS MFA is offered only for verified linked identities. 4. <code>beginMfaOtp()</code> issues an MFA-bound OTP when needed. 5. <code>completeMfa()</code> consumes the one-time transaction and creates the session.</p>
<h3 id="passkeys">Passkeys</h3>
<p>The browser runtime coordinates <code>navigator.credentials.create()</code> and <code>navigator.credentials.get()</code>. A configured server-side <code>PasskeyProvider</code> must verify the challenge, RP ID, origin, signature, user presence or verification, counter, and credential ownership.</p>
<p>Multi-process deployments must provide a shared <code>PasskeyChallengeStore</code>; the default memory implementation is process-local. Missing passkey providers return a controlled <code>503</code> response rather than crashing the route.</p>
<h3 id="protect-long-lived-secrets">Protect long-lived secrets</h3>
<pre data-language="ts"><code>import &#123; createAuthSecretProtector &#125; from &quot;@wrnexus/auth&quot;;
import &#123; createKeyring &#125; from &quot;@wrnexus/encryption&quot;;
const keyring = createKeyring([
&#123;
id: &quot;auth-2026-01&quot;,
secret: process.env.AUTH_ENCRYPTION_KEY!,
active: true,
&#125;,
]);
const auth = createAuthEngine(&#123;
store: new SqlAuthStore(getDb()),
secret: process.env.AUTH_SECRET!,
secretProtector: createAuthSecretProtector(keyring),
&#125;);</code></pre>
<p>TOTP seeds and OAuth access/refresh tokens are protected before persistence. Keep old keys available during rotation.</p>
<h3 id="custom-http-integration">Custom HTTP integration</h3>
<p><code>createAuthHttpHandlers()</code> remains available for custom route paths or response behavior. Prefer package routes for standard flows; copied application API files are unnecessary.</p>
<h3 id="development">Development</h3>
<pre data-language="bash"><code>bun run auth:dev
bun run validate:auth</code></pre>
<p>Read [SECURITY.md](./SECURITY.md) before production deployment.</p>
<h3 id="package-owned-ui-blocks-and-route-helpers">Package-owned UI blocks and route helpers</h3>
<p>Authentication forms continue to compose <code>@wrnexus/ui</code> inputs, buttons, cards, alerts, badges, avatars, and PIN controls. The package also provides:</p>
<ul>
<li><code>&lt;AuthShell /&gt;</code></li>
<li><code>&lt;AuthProviderButtons /&gt;</code></li>
<li><code>&lt;AuthSecurityNotice /&gt;</code></li>
<li>complete sign-in, sign-up, MFA, passkey, recovery, account-status, session, and impersonation blocks</li>
</ul>
<p>Server helpers include <code>authRoute</code>, <code>authSuccess</code>, <code>authFailure</code>, <code>requireAuthUser</code>, <code>optionalAuthUser</code>, <code>currentAuthSession</code>, and <code>authComponentProps</code>.</p></section><section id="api" class="api"><h2>Complete TypeScript API</h2><p>Generated from the exact installed package declarations.</p><pre data-language="typescript"><code>import &#123; A as AuthEngine &#125; from './engine-NjrTiSrg.js';
export &#123; c as createAuthEngine, i as inferIdentityType, n as normalizeEmail, a as normalizeIdentity, b as normalizePhone, d as normalizeUsername, p as publicUser, s as safeAuthReturnTo &#125; from './engine-NjrTiSrg.js';
export &#123; VERIFICATION_SESSION_COOKIE, clearVerificationSession, getVerificationUser, startVerificationSession &#125; from './server/index.js';
import &#123; m as AuthRiskSignals, n as AuthRiskDecision, d as AuthSession, b as AuthUser &#125; from './types-CuQWJQV1.js';
export &#123; o as AUTH_SECURITY_EVENT_TYPES, p as AuthAccountStatus, q as AuthClock, r as AuthDeliveryMessage, s as AuthDeliveryProvider, t as AuthEngineOptions, c as AuthIdentity, u as AuthIdentityType, v as AuthImpersonationDecision, w as AuthMfaMethod, j as AuthPublicUser, x as AuthRandom, y as AuthResult, z as AuthRiskLevel, l as AuthSecretProtector, i as AuthSecurityEvent, B as AuthSecurityEventType, A as AuthSessionVerificationHandler, C as AuthSignedInHandler, D as AuthSignedOutHandler, a as AuthStore, E as AuthSuccessfulSignUpAction, F as AuthSuccessfulSignUpHandler, G as AuthTokenPurpose, H as AuthTokenUrlInput, k as AuthenticatedContext, K as KnownAuthSecurityEventType, L as LoginAttempt, I as LoginInput, M as MemoryPasskeyChallengeStore, h as OAuthAccount, O as OneTimeToken, e as OtpChallenge, J as PasskeyAuthenticationOptions, N as PasskeyChallengeKind, Q as PasskeyChallengeRecord, S as PasskeyChallengeStore, g as PasskeyCredential, U as PasskeyProvider, V as PasskeyRegistrationOptions, W as PasskeyVerificationResult, X as PasswordBreachProvider, P as PasswordCredential, R as RecoveryCodeRecord, Y as RegisterInput, f as TotpCredential, T as TrustedDevice, Z as assertPasskeyProvider &#125; from './types-CuQWJQV1.js';
export &#123; MemoryAuthStore &#125; from './stores/memory.js';
export &#123; SqlAuthStore, SqlAuthStoreOptions &#125; from './stores/sql.js';
export &#123; AUTH_SESSION_KEY, AuthRequiredError, authSession, clearAuthSession, establishAuthSession, getAuthSession, getAuthUser, isAuthenticatedContext, requireAuth, requireAuthUser &#125; from './middleware.js';
export &#123; d as AuthHttpOptions, a as AuthPasskeyHttpOptions, A as AuthSchemaOverrides, b as AuthSchemaSet, e as authBrowserSchemaDescriptors, f as authBrowserSchemaMap, g as authSchemas, h as authenticatorConfirmSchema, i as authenticatorDisableSchema, j as authenticatorSetupSchema, k as changePasswordSchema, c as createAuthHttpHandlers, l as emptyActionSchema, m as impersonationStartSchema, n as invitationAcceptSchema, o as loginSchema, p as magicLinkConsumeSchema, q as magicLinkRequestSchema, r as mfaOtpRequestSchema, s as mfaSchema, t as otpIssueSchema, u as otpLoginCompleteSchema, v as otpLoginRequestSchema, w as otpSchema, x as passkeyAuthenticationOptionsSchema, y as passkeyAuthenticationVerifySchema, z as passkeyRegistrationOptionsSchema, B as passkeyRegistrationVerifySchema, C as passwordResetRequestSchema, D as passwordResetSchema, E as recoveryCodesSchema, F as registerSchema, G as resolveAuthSchemas, H as sessionRevokeSchema, I as signUpSchema, J as verificationRequestSchema, K as verificationTokenSchema &#125; from './index-DuuY2a1R.js';
export &#123; AuthAuditIssue, AuthConfig, AuthPluginOptions, AuthRoutesConfig, authComponentsDir, authPlugin, configureAuthRuntime, validateProductionAuthConfig &#125; from './plugin.js';
export &#123; DefaultAuthRouteOptions, clearDefaultAuthEngine, getDefaultAuthEngine, getDefaultAuthRouteOptions, getDefaultAuthSchemas, hasDefaultAuthEngine, setDefaultAuthEngine, setDefaultAuthRouteOptions, setDefaultAuthSchemas, tryGetDefaultAuthEngine &#125; from './runtime.js';
export &#123; createAuthSecretProtector &#125; from './protector.js';
export &#123; decodeBase32, encodeBase32, generateTotp, generateTotpSecret, totpUri, verifyTotp &#125; from './totp/index.js';
import &#123; Context &#125; from '@wrnexus/core';
import '@wrnexus/oauth';
import '@wrnexus/db';
import '@wrnexus/validation';
import '@wrnexus/plugin';
import '@wrnexus/encryption';
interface RiskPolicy &#123;
captchaThreshold: number;
mfaThreshold: number;
blockThreshold: number;
&#125;
declare function evaluateAuthRisk(signals?: AuthRiskSignals, policy?: RiskPolicy): AuthRiskDecision;
type AuthRouteName = &quot;signIn&quot; | &quot;signUp&quot; | &quot;signOut&quot; | &quot;forgotPassword&quot; | &quot;resetPassword&quot; | &quot;verifyEmail&quot; | &quot;verifyPhone&quot; | &quot;twoFactor&quot; | &quot;sessions&quot; | &quot;passkeys&quot;;
declare function authRoute(name: AuthRouteName, options?: &#123;
basePath?: string;
overrides?: Partial&lt;Record&lt;AuthRouteName, string&gt;&gt;;
&#125;): string;
declare function authSuccess&lt;T extends Record&lt;string, unknown&gt;&gt;(data: T, init?: ResponseInit): Response;
declare function authFailure(code: string, message: string, status?: number, details?: Record&lt;string, unknown&gt;): Response;
declare function optionalAuthUser(ctx: Context): AuthUser | null;
declare function currentAuthSession(engine: AuthEngine, sessionId: string | undefined): Promise&lt;AuthSession | null&gt;;
declare function authComponentProps(input: Record&lt;string, unknown&gt;, defaults?: &#123;
color?: string;
size?: string;
class?: string;
&#125;): Record&lt;string, unknown&gt;;
export &#123; AuthEngine, AuthRiskDecision, AuthRiskSignals, type AuthRouteName, AuthSession, AuthUser, type RiskPolicy, authComponentProps, authFailure, authRoute, authSuccess, currentAuthSession, evaluateAuthRisk, optionalAuthUser &#125;;
</code></pre></section><section id="examples" class="examples"><h2>Examples</h2><p>Copy-ready examples from the installed package documentation.</p><div class="example-grid"><article class="example-card"><h3>Signup business logic and verification-only sessions</h3><pre data-language="ts"><code>const auth = createAuthEngine(&#123;
store: () =&gt; new SqlAuthStore(getDb()),
secret: process.env.AUTH_SECRET!,
requireVerifiedEmail: true,
onSignUp(ctx, user) &#123;
// Application business logic can run here after successful registration.
return &#123; verificationSession: true, redirectTo: &quot;/verify-email&quot; &#125;;
&#125;,
delivery: &#123;
async send(message) &#123;
// message.channel, template, destination, user, expiresAt
// Verification uses message.token and message.url; OTP flows use message.code.
// Render your branded content here before passing it to your provider.
&#125;,
&#125;,
&#125;);</code></pre></article><article class="example-card"><h3>Signup business logic and verification-only sessions</h3><pre data-language="bash"><code>bun add @wrnexus/auth</code></pre></article><article class="example-card"><h3>Signup business logic and verification-only sessions</h3><pre data-language="ts"><code>// app/lib/auth.ts
import &#123; createAuthEngine, MemoryAuthStore &#125; from &quot;@wrnexus/auth&quot;;
export const auth = createAuthEngine(&#123;
store: new MemoryAuthStore(),
secret: process.env.AUTH_SECRET!,
issuer: &quot;My application&quot;,
onSignedIn(ctx, returnTo) &#123;
const safe = returnTo?.startsWith(&quot;/&quot;) &amp;&amp; !returnTo.startsWith(&quot;//&quot;) ? returnTo : &quot;/account&quot;;
return Response.redirect(new URL(safe, ctx.url), 303);
&#125;,
onSignedOut(ctx) &#123;
return Response.redirect(new URL(&quot;/sign-in&quot;, ctx.url), 303);
&#125;,
onSuccessfulSignUp() &#123;
return &#123;
autoSignIn: true,
redirectTo: &quot;/account&quot;,
&#125;;
&#125;,
delivery: &#123;
async send(message) &#123;
// Queue email/SMS through your provider. Never log message.code or message.token.
&#125;,
&#125;,
&#125;);</code></pre></article><article class="example-card"><h3>Successful signup behavior</h3><pre data-language="ts"><code>onSuccessfulSignUp(ctx, user) &#123;
return &#123;
autoSignIn: true,
redirectTo: &quot;/account&quot;,
&#125;;
&#125;</code></pre></article><article class="example-card"><h3>Successful signup behavior</h3><pre data-language="ts"><code>// wrnexus.config.ts
import type &#123; AuthConfig &#125; from &quot;@wrnexus/auth&quot;;
import type &#123; AppConfig &#125; from &quot;@wrnexus/styles&quot;;
import &#123; auth &#125; from &quot;./app/lib/auth.ts&quot;;
const config = &#123;
auth: &#123;
engine: auth,
routes: true,
middleware: true,
migrations: false,
&#125;,
&#125; satisfies AppConfig &amp; &#123; auth: AuthConfig &#125;;
export default config;</code></pre></article><article class="example-card"><h3>Successful signup behavior</h3><pre data-language="ts"><code>import &#123; createAuthEngine, SqlAuthStore &#125; from &quot;@wrnexus/auth&quot;;
import &#123; getDb &#125; from &quot;@wrnexus/db&quot;;
export const auth = createAuthEngine(&#123;
store: new SqlAuthStore(getDb()),
secret: process.env.AUTH_SECRET!,
&#125;);</code></pre></article></div></section></article></div>
<aside class="on-this-page"><h2>On this page</h2><nav><a class="toc-level-2" href="#guide">Guide</a><a class="toc-level-4" href="#new-browser-verification-and-device-trust">New-browser verification and device trust</a><a class="toc-level-4" href="#signup-business-logic-and-verification-only-sessions">Signup business logic and verification-only sessions</a><a class="toc-level-3" href="#capabilities">Capabilities</a><a class="toc-level-3" href="#install">Install</a><a class="toc-level-3" href="#default-configuration">Default configuration</a><a class="toc-level-4" href="#successful-signup-behavior">Successful signup behavior</a><a class="toc-level-3" href="#sql-production-configuration">SQL production configuration</a><a class="toc-level-3" href="#delivered-action-urls">Delivered action URLs</a><a class="toc-level-3" href="#built-in-validation">Built-in validation</a><a class="toc-level-3" href="#route-controls">Route controls</a><a class="toc-level-3" href="#package-endpoints">Package endpoints</a><a class="toc-level-3" href="#components">Components</a><a class="toc-level-3" href="#captcha-and-risk">CAPTCHA and risk</a><a class="toc-level-3" href="#mfa">MFA</a><a class="toc-level-3" href="#passkeys">Passkeys</a><a class="toc-level-3" href="#protect-long-lived-secrets">Protect long-lived secrets</a><a class="toc-level-3" href="#custom-http-integration">Custom HTTP integration</a><a class="toc-level-3" href="#development">Development</a><a class="toc-level-3" href="#package-owned-ui-blocks-and-route-helpers">Package-owned UI blocks and route helpers</a><a class="toc-level-2" href="#api">Complete API</a><a class="toc-level-2" href="#examples">Examples</a></nav></aside>
</main>
<footer><div class="footer-brand"><span class="footer-mark" aria-hidden="true">W</span><p><strong>WRNexusJS 0.8.72</strong><span>Complete API documentation generated from installed package declarations.</span></p></div><nav aria-label="Footer"><a href="/packages">All packages</a><a href="/getting-started">Get started</a><a href="/security">Security</a><a href="/support">Support</a><a href="/llms.txt">AI guide</a></nav><p class="footer-meta">Private Developer Preview · Bun-native</p></footer>
</div>
}
}