Guides
Examples
Patterns you can adapt. The rule across all of them: the API key and session token live on the server; the browser only ever talks to your backend.
Adapt, don't copy blindly. These show the shape of an integration with
zkauth-client. Match field names to the responses in the API reference.Next.js: server route + cookie
Do the login on the server and store the session in an http-only cookie. The key never reaches the client.
app/api/login/route.tsts
// app/api/login/route.tsimport { cookies } from 'next/headers'import { ZKAuthSDK } from 'zkauth-client'
const zkauth = new ZKAuthSDK({ apiKey: process.env.ZKAUTH_API_KEY! })
export async function POST(req: Request) { const { email, password } = await req.json() const res = await zkauth.login({ email, password, deviceInfo: { deviceName: 'Web', deviceType: 'desktop' }, })
// Keep the token server-side in an http-only cookie. cookies().set('zkauth_session', res.data.session.token, { httpOnly: true, secure: true, sameSite: 'lax', path: '/', })
return Response.json({ user: res.data.user })}React: a login form
The form posts credentials to your own route above; it never sees a ZKAuth key.
login-form.tsxtsx
'use client'import { useState } from 'react'
export function LoginForm() { const [error, setError] = useState('')
async function onSubmit(e: React.FormEvent<HTMLFormElement>) { e.preventDefault() const form = new FormData(e.currentTarget) const res = await fetch('/api/login', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email: form.get('email'), password: form.get('password'), }), }) if (res.ok) location.href = '/dashboard' else setError('Invalid credentials') }
return ( <form onSubmit={onSubmit}> <input name="email" type="email" required /> <input name="password" type="password" required /> <button type="submit">Sign in</button> {error && <p role="alert">{error}</p>} </form> )}Express: protect a route
Validate the session cookie on each protected request by calling the engine’s /auth/mewith the user’s bearer token.
server.tsts
import express from 'express'
const BASE = process.env.ZKAUTH_BASE_URL ?? 'https://api.zkauth.dev'const app = express()
// A server validates many users' tokens, so check each one against the// engine's /auth/me rather than the SDK's single in-memory session.async function requireUser(req, res, next) { const token = req.cookies?.zkauth_session if (!token) return res.status(401).json({ error: 'unauthenticated' })
const r = await fetch(`${BASE}/api/v1/auth/me`, { headers: { 'x-api-key': process.env.ZKAUTH_API_KEY, Authorization: `Bearer ${token}`, }, }) if (!r.ok) return res.status(401).json({ error: 'invalid session' })
req.user = (await r.json()).data?.user next()}
app.get('/api/profile', requireUser, (req, res) => res.json({ user: req.user }))Other languages
No SDK for your stack yet? Every example above maps to plain HTTPS calls with an x-api-key header. See the API reference for the request and response shapes.