Skip to main content
AuthProvider gives your app session management: sign-in, sign-up, sign-out, token refresh, MFA, and SSR hydration. Wrap your app, use useAuth() to read state, and use form(auth.signIn) for login — same patterns as the rest of the framework.

Quick start

1. Wrap your app

2. Build a login form

3. Read auth state anywhere

auth.signIn is an SdkMethodform() works with it directly for validation, submission, and error handling. No manual fetch calls, no state wiring.

How it works

Auth state machine

StatusMeaning
idleInitial state before any auth check (SSR/Node only)
loadingAuth operation in progress
authenticatedValid session, auth.user is populated
unauthenticatedNo valid session
mfa_requiredSign-in succeeded but MFA verification needed
errorAuth operation failed, auth.error has details

JWT session lifecycle

Vertz uses httpOnly cookies for JWT tokens — the client never reads the token directly. The server returns expiresAt in the response body, and the client schedules proactive refresh:
Token refresh is automatic:
  • Scheduled 10 seconds before expiry
  • Deduplicated (concurrent calls share one in-flight request)
  • Deferred when the tab is hidden (refreshes on focus if stale)
  • Deferred when offline (refreshes on reconnect)

API reference

AuthProvider

Wraps your app with auth context. All useAuth() calls must be inside an AuthProvider.
PropTypeDefaultDescription
basePathstring'/api/auth'Base URL for auth endpoints
accessControlbooleanfalseEnable automatic access set management
childrenunknownApp content

useAuth()

Returns reactive auth state. All signal properties are auto-unwrapped by the compiler — no .value needed.
PropertyTypeDescription
userUser | nullCurrent user or null
statusAuthStatusCurrent auth state
isAuthenticatedbooleantrue when status is 'authenticated'
isLoadingbooleantrue when status is 'loading'
errorAuthClientError | nullLast auth error
signInSdkMethodSign in with email/password
signUpSdkMethodCreate account with email/password
signOut() => Promise<void>Clear session and cookies
refresh() => Promise<void>Manually refresh the token
mfaChallengeSdkMethodSubmit MFA TOTP code
forgotPasswordSdkMethodRequest password reset email
resetPasswordSdkMethodReset password with token

AuthGate

Gates rendering on auth state resolution. Shows fallback while auth is loading, children once resolved.

ProtectedRoute

Route guard that handles loading, authentication, entitlements, and redirect — all in one component. Wraps useAuth(), the router, and can() so you don’t have to.
PropTypeDefaultDescription
loginPathstring'/login'Where to redirect unauthenticated users
fallback() => unknownnullRendered while auth is resolving
childrenunknownRendered when authenticated
requiresEntitlement[]Entitlements the user must have (checked via can()). Type-safe when codegen is active.
forbidden() => unknownnullRendered when authenticated but lacking entitlements
returnTobooleantrueAppend ?returnTo=<currentPath> to the login redirect
Behavior:
Auth stateResult
idle / loadingRenders fallback
authenticated (entitlements met)Renders children
authenticated (entitlements denied)Renders forbidden (no redirect)
unauthenticated / error / mfa_requiredNavigates to loginPath
ProtectedRoute does NOT redirect when entitlements fail — it renders forbidden instead. This avoids redirect loops where a logged-in user is sent to login but still lacks permissions after signing in.
With entitlement checks:
Without a provider (fail-open): If there’s no AuthProvider in the tree, ProtectedRoute renders children and logs a dev-mode warning. This matches AuthGate’s fail-open behavior. SSR: During server rendering, ProtectedRoute renders the fallback. The redirect fires client-side after hydration.

Auth methods as SdkMethods

Every auth method (signIn, signUp, mfaChallenge, forgotPassword, resetPassword) is an SdkMethod. This means:
  1. form() works directly — validation, submission, field errors, all automatic
  2. .url and .method are available for <form action={...} method={...}>
  3. .meta.bodySchema provides the validation schema

Input types

MethodRequired fields
signIn{ email: string, password: string }
signUp{ email: string, password: string }
mfaChallenge{ code: string }
forgotPassword{ email: string }
resetPassword{ token: string, password: string }

MFA flow

When the server requires MFA, signIn transitions to mfa_required instead of authenticated:

Password reset flow

Request reset email

Reset with token


SSR hydration

When using SSR, the server injects the session into the page so the client doesn’t need an initial /api/auth/session fetch.

Server side

What happens on the client

  1. Server injects window.__VERTZ_SESSION__ with { user, expiresAt }
  2. AuthProvider reads it on initialization — no fetch needed
  3. Auth state is 'authenticated' immediately — no loading flicker
  4. Token refresh is scheduled from the hydrated expiresAt
When there’s no session (guest user), AuthProvider transitions to 'unauthenticated' immediately.

Access control integration

When accessControl is enabled, AuthProvider automatically manages the access set:
This:
  • Wraps children in AccessContext.Provider
  • Fetches the access set from ${basePath}/access-set after successful auth
  • Clears the access set on sign out
  • Hydrates from window.__VERTZ_ACCESS_SET__ during SSR
Use can() anywhere inside the provider:
See the Access Control guide for full details on can(), AccessGate, and entity-scoped checks.

Error handling

Auth errors are available via auth.error:

Error codes

CodeWhen
INVALID_CREDENTIALSWrong email/password
USER_EXISTSEmail already registered
MFA_REQUIREDMFA verification needed (status transitions to mfa_required)
INVALID_MFA_CODEWrong MFA code
RATE_LIMITEDToo many attempts (retryAfter is set)
NETWORK_ERRORFetch failed (offline, DNS, etc.)
SERVER_ERRORUnexpected server error

Common patterns

Logout button

Conditional rendering based on auth

Sign-up with extra fields

The signUp input accepts { email, password, ...extra }, but reserved auth fields such as role, plan, emailVerified, id, and timestamps are ignored by the auth handler.

Next steps

Multi-Tenancy

TenantProvider, useTenant(), and TenantSwitcher for multi-tenant apps.

Server-Side Auth

Configure JWT sessions, RBAC, plans, and usage limits.

Access Control

Use can() and AccessGate in your UI components.

Forms

Deep dive into form() — validation, fields, progressive enhancement.

SSR

Server-side rendering setup and hydration.