Get started
Quick start
The whole lifecycle in four calls. Each one carries a proof, never the password.
Before you start
Install
zkauth-client and set your keys. Installation covers it in a minute.Register a user
The client derives a zero-knowledge proof from the password locally and sends only that proof; the engine stores a verifier.
ts
import { zkauth } from './lib/zkauth'
await zkauth.register({ email: 'ada@example.com', password: 'correct horse battery staple', deviceInfo: { deviceName: 'Chrome on Mac', deviceType: 'desktop' },})Log in
Login repeats the handshake. The engine verifies the proof, applies replay protection, and returns a session token.
ts
const res = await zkauth.login({ email: 'ada@example.com', password: 'correct horse battery staple', deviceInfo: { deviceName: 'Chrome on Mac', deviceType: 'desktop' },})
// The token lives on the instance; persist it in an http-only cookie too.const token = res.data.session.tokenRead the current user
The client keeps the session after login, so read the current user with no arguments.
ts
const user = await zkauth.getCurrentUser() // uses the active sessionconsole.log(user?.email)Log out
Invalidate the session when the user signs out.
ts
await zkauth.logout()Handle callbacks and hosted handoff
Set a primary redirect URL in the dashboard, then add it to the allowlist.
- ZKAuth sends users there after email verification, device approval, device denial, and password reset links.
- If no safe redirect is configured, ZKAuth shows a hosted fallback page instead of redirecting to an unknown URL.
- Hosted sign-up/sign-in helper pages and hosted forgot-password/reset pages can run through the project-bound hosted proxy without exposing project API keys.
- Hosted sign-in can return a single-use handoff code to an allowlisted callback. Redeem it from your backend with the project API key, then create your app session cookie without exposing the bearer token in browser storage or callback URLs.
- Display callback errors only through allowlisted copy, not raw query text.
- After engine sign-in, hosted UI can show a memory-only account security helper for profile, account stats, recent activity, sessions, devices, and recovery.
- That helper also covers shown-once recovery-code export, TOTP setup/reset, MFA disable, hosted-origin passkeys, and user API-key helper controls.
- Fresh-session guarded actions, such as terminating other active sessions, still require the engine to confirm a recent first-factor session.
- Configure exact browser origins for your production and preview domains; origins must not include paths or wildcards.
ts
import { redeemZKAuthHostedHandoff } from '@zkauth/node'
const callbackErrorCopy: Record<string, string> = { invalid_token: 'The authentication link is invalid or expired.', token_expired: 'The authentication link is invalid or expired.', token_consumed: 'The authentication link is invalid or expired.', device_denied: 'The device request was denied.',}
function safeCallbackError(error: string | null) { return error && callbackErrorCopy[error] ? callbackErrorCopy[error] : 'The authentication action could not be completed. Try again.'}
export async function GET(request: Request) { const url = new URL(request.url) const params = url.searchParams const action = params.get('zkauth_action') const code = params.get('code')
if (code) { const handoff = await redeemZKAuthHostedHandoff( { apiKey: loadServerOnlyProjectKey(), baseUrl: loadServerOnlyApiBaseUrl(), }, code, )
const response = Response.redirect(new URL('/app', request.url)) response.headers.append( 'Set-Cookie', 'zkauth_session=' + encodeURIComponent(handoff.sessionToken) + '; Path=/; HttpOnly; Secure; SameSite=Lax', ) return response }
if (action === 'password_reset') { return showResetPasswordForm(params.get('token')) }
if (params.get('success') === 'true') { return Response.redirect(new URL('/app', request.url)) }
return showAuthError(safeCallbackError(params.get('error')))}Done
You ran a full zero-knowledge auth cycle. Next, decide which method fits your product in Authentication, or wire a framework in Examples.