zkauth-client
v1.5.0
Published
JavaScript/TypeScript SDK for tenant-bound ZKAuth-H authentication
Maintainers
Readme
zkauth-client
JavaScript and TypeScript SDK for ZKAuth-H zero-knowledge authentication.
New Session / AI Handoff
Before making changes, read CONTEXT.md. It summarizes the SDK
role, current version, security invariants, and the developer-flow tests used
with the dashboard and hosted engine.
The current production engine is:
https://api.zkauth.devThe SDK sends the project API key with x-api-key and sends user session JWTs with Authorization: Bearer <token> for authenticated user routes.
Browser-hosted flows can instead use the ZKAuth dashboard hosted proxy. In that mode the SDK still generates commitments and proofs locally, but it calls the dashboard proxy with a project slug and public client ID. The project API key is injected server-side by ZKAuth and is never placed in browser code.
For production projects, configure a primary redirect URL and allowlist in the ZKAuth dashboard. Email verification, device approval or denial, and password reset links are processed by ZKAuth first, then redirected only to the exact allowlisted callback URL. If no safe callback is configured, ZKAuth shows its hosted fallback page instead of redirecting to an unknown URL.
Installation
npm install zkauth-clientNode.js installs also try to install the optional native @node-rs/argon2
package. When available, the SDK uses that native Argon2id path for password
hashing; browser builds keep the portable JavaScript implementation.
Integration Paths
| App shape | Install | First import | Boundary |
| --------------------------- | ----------------------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------- |
| Direct SDK or server worker | npm install zkauth-client | import { ZKAuthSDK } from "zkauth-client" | Server-side direct API key, or browser hosted proxy mode. |
| Next.js App Router | npm install @zkauth/nextjs @zkauth/node | import { withRouteAuth } from "@zkauth/nextjs" | Proxy redirects plus Route Handler, Server Component, or Server Action re-checks. |
| Vite React UI | npm install @zkauth/react | import { ZKAuthProvider, SignIn } from "@zkauth/react" | Browser-safe app proxy routes. No project API key in React code. |
| Express or Hono API | npm install @zkauth/express or npm install @zkauth/hono | import { authMiddleware } from "@zkauth/express" | Server middleware verifies sessions and incoming API keys. |
Basic Usage
import { ZKAuthSDK } from "zkauth-client";
const zkauth = new ZKAuthSDK({
apiKey: process.env.ZKAUTH_API_KEY!,
baseUrl: process.env.ZKAUTH_BASE_URL || "https://api.zkauth.dev",
});
const registered = await zkauth.register({
email: "[email protected]",
password: "SecurePassword123!",
deviceInfo: {
deviceName: "Chrome on macOS",
deviceType: "desktop",
browserName: "Chrome",
osName: "macOS",
},
});
if (registered.data.verificationToken) {
await zkauth.verifyEmail(registered.data.verificationToken);
}
const loggedIn = await zkauth.login({
email: "[email protected]",
password: "SecurePassword123!",
deviceInfo: {
deviceName: "Chrome on macOS",
deviceType: "desktop",
browserName: "Chrome",
osName: "macOS",
},
});
console.log("Registered user:", registered.data.userId);
console.log("Login successful:", zkauth.isAuthenticated());Hosted Proxy Mode
Use this mode only from browser-hosted ZKAuth pages or browser code that should not receive a project API key:
import { ZKAuthSDK } from "zkauth-client";
const zkauth = new ZKAuthSDK({
hostedProxy: {
baseUrl: "https://zkauth.dev",
projectSlug: "your-project-slug",
clientId: "your_public_client_id",
},
});
await zkauth.login({
email: "[email protected]",
password,
deviceInfo: {
deviceName: "Chrome on macOS",
deviceType: "desktop",
},
});Hosted proxy mode rewrites SDK engine calls such as
/api/v1/auth/login to
/api/hosted/projects/:projectSlug/proxy/auth/login?clientId=:clientId.
It does not send x-api-key from the browser. Authenticated user routes still
send the user session JWT with Authorization: Bearer <token>.
Current Backend Contract
Core routes used by this SDK:
GET /health
GET /api/v1/client/me
POST /api/v1/auth/register
GET /api/v1/auth/salt/:email
POST /api/v1/auth/login
GET /api/v1/auth/me
POST /api/v1/auth/logout
POST /api/v1/auth/refresh
GET /api/v1/auth/verify-email/:token
POST /api/v1/auth/verify-mfa
POST /api/v1/password/forgot-password
GET /api/v1/password/verify-reset-token
POST /api/v1/password/reset-password
GET /api/v1/devices
POST /api/v1/devices/register
POST /api/v1/devices/verify
DELETE /api/v1/devices/:deviceId
GET /api/v1/security/mfa/status
GET /api/v1/opaque/status
POST /api/v1/opaque/register/response
POST /api/v1/opaque/register/finish
POST /api/v1/opaque/login/start
POST /api/v1/opaque/login/finish
POST /api/v1/webauthn/register/options
POST /api/v1/webauthn/register/verify
POST /api/v1/webauthn/authenticate/options
POST /api/v1/webauthn/authenticate/verifyAuthentication Flow
Registration:
- The SDK fetches the tenant/client ID from
/api/v1/client/me. - The SDK generates a 32-byte salt.
- The SDK derives the password hash with Argon2id using the current backend parameters: memory
19456, time cost2, parallelism1, hash length32. - The SDK computes the tenant-bound Poseidon commitment.
- The SDK adds a deterministic device fingerprint when the application does not provide one.
- The SDK sends only the email, salt, commitment, and device metadata to the backend.
Login:
- The SDK fetches the tenant/client ID.
- The SDK fetches the user's salt.
- The SDK regenerates the password hash and commitment locally.
- The SDK generates a Groth16 proof using the bundled auth circuit.
- The SDK reuses the same deterministic device fingerprint for exact trusted-device matching.
- The backend verifies the proof, timestamp, nonce, tenant binding, device trust, and replay registry before issuing a session JWT.
API
Constructor
new ZKAuthSDK({
apiKey?: 'zka_live_or_test_key',
baseUrl?: 'https://api.zkauth.dev',
timeout?: 30000,
debug?: false,
clientId?: 'optional-client-uuid',
hostedProxy?: {
baseUrl?: 'https://zkauth.dev',
projectSlug: 'your-project-slug',
clientId: 'public-client-id',
proxyPath?: '/api/hosted/projects/your-project-slug/proxy'
}
});baseUrl must be HTTPS in production. Plain HTTP is accepted only for local
development hosts such as localhost or 127.0.0.1.
Set either apiKey for direct server-side/API usage or hostedProxy for
browser-safe hosted proxy usage.
Core Methods
await zkauth.register(params);
await zkauth.login(params);
await zkauth.logout();
await zkauth.getCurrentUser();
zkauth.isAuthenticated();
zkauth.getSession();
await zkauth.verifyEmail(token);
await zkauth.getDevices();
await zkauth.healthCheck();Circuit Assets
zkauth-client packages the auth and device Groth16 circuit assets under
circuits/. The root package exports helpers for code that wants to inspect or
preload those assets:
import { getAuthCircuitFiles, getDeviceCircuitFiles } from "zkauth-client";
const authCircuits = getAuthCircuitFiles();
const deviceCircuits = getDeviceCircuitFiles();Node.js resolves these paths from the installed package in
node_modules/zkauth-client/circuits. Browser builds resolve them as
/circuits/..., so your app must serve copied circuit assets when you call the
low-level proof helpers directly.
OPAQUE Helpers
These methods expose the current backend OPAQUE routes. The caller is responsible for creating the OPAQUE client messages with a compatible OPAQUE library.
await zkauth.opaqueStatus();
await zkauth.opaqueRegistrationResponse({ registrationRequest, email, userId });
await zkauth.opaqueRegistrationFinish({
email,
userId,
registrationRecord,
serverStaticPublicKey,
});
await zkauth.opaqueLoginStart({ startLoginRequest, email, userId });
await zkauth.opaqueLoginFinish({ sessionId, finishLoginRequest });WebAuthn Helpers
These methods expose the current backend WebAuthn routes. Browser applications still need to call navigator.credentials.create() and navigator.credentials.get() with the returned options.
await zkauth.webAuthnRegistrationOptions({ userId, email, displayName });
await zkauth.webAuthnRegistrationVerify({ userId, response });
await zkauth.webAuthnAuthenticationOptions({ userId, email });
await zkauth.webAuthnAuthenticationVerify({ userId, email, response });Error Handling
import { ZKAuthError, ZKAuthErrorCode } from "zkauth-client";
try {
await zkauth.login({ email, password });
} catch (error) {
if (error instanceof ZKAuthError) {
if (error.code === ZKAuthErrorCode.UNAUTHORIZED) {
// Invalid credentials or expired session.
}
}
}Security Notes
- Passwords are not sent to the server.
- Do not log or expose API keys, session JWTs, verification tokens, reset tokens, or device approval tokens.
- The proof is tenant-bound through the client hash in the circuit public inputs.
- The backend performs nonce, timestamp, replay, public-signal, and Groth16 verification.
- The backend fails closed for production Redis replay protection.
- This package does not claim post-quantum security, external audit status, NIST AAL certification, or universal hardware-passkey compatibility.
Development
npm install
npm run build
npm testLicense
MIT
