Skip to content

Authentication

zod-vault provides a unified auth client with passkeys (WebAuthn) and email/password support.

import { VaultClient } from "@zod-vault/client";
const client = new VaultClient({
serverUrl: "https://vault.example.com",
rpName: "My App", // For passkey prompts
preferPasskey: true, // Try passkey first
});
try {
const result = await client.registerEmail("user@example.com", "password123");
console.log("Registered:", result.user);
} catch (error) {
console.error("Registration failed:", error.message);
}
try {
const result = await client.loginEmail("user@example.com", "password123");
console.log("Logged in:", result.user);
} catch (error) {
console.error("Login failed:", error.message);
}

Passkeys are the recommended auth method — phishing-resistant and no password to remember.

// User must be logged in first (via email)
await client.registerPasskey();
// Browser prompts for biometric/security key
await client.loginPasskey();
// Browser prompts for saved passkey
import { useVaultAuth } from "@zod-vault/client";
function AuthComponent() {
const {
isAuthenticated, // boolean
isLoading, // boolean
user, // { id, email } | null
error, // Error | null
login, // (email, password) => Promise
register, // (email, password) => Promise
logout, // () => Promise
} = useVaultAuth(client);
if (isLoading) return <Loading />;
if (!isAuthenticated) {
return (
<button onClick={() => login("user@example.com", "password")}>
Login
</button>
);
}
return (
<div>
<p>Logged in as {user.email}</p>
<button onClick={logout}>Logout</button>
</div>
);
}
const token = client.getToken();
// Pass this to vault() getToken option
const user = client.getUser();
// => { id: "...", email: "user@example.com" } | null
if (client.isAuthenticated()) {
// User is logged in
}
await client.logout();
// Clears tokens and notifies server

Tokens refresh automatically. To force a refresh:

await client.refreshToken();

Subscribe to auth state changes:

const unsubscribe = client.subscribe((state) => {
console.log("Auth changed:", state.isAuthenticated);
});
// Later
unsubscribe();
try {
await client.loginEmail(email, password);
} catch (error) {
if (error.code === "INVALID_CREDENTIALS") {
// Wrong email/password
} else if (error.code === "USER_NOT_FOUND") {
// No account with this email
} else if (error.code === "NETWORK_ERROR") {
// Server unreachable
}
}
  1. Prefer passkeys — More secure than passwords
  2. Store recovery key separately — Not tied to auth account
  3. Handle offline state — Auth may fail without network
  4. Clear sensitive data on logout — Consider clearing vault too