client.auth
Authentication is exposed through client.auth.zk. See the
Authentication guide for usage.
interface AuthUser { username: string; /** Decimal-string Poseidon commitment — the user's stable id. */ commitment: string;}Methods
Section titled “Methods”register(params)
Section titled “register(params)”register(params: { username: string; password: string; email?: string | null; login?: boolean; // default: true}): Promise<AuthUser>Derives the identity, registers the commitment, and (unless login: false)
signs in. Throws if the username is taken.
login(username, password, opts?)
Section titled “login(username, password, opts?)”login(username: string, password: string, opts?: { rememberMe?: boolean }): Promise<AuthUser>Re-derives the identity, proves it against a fresh server challenge, and
establishes the session and identity. rememberMe: true requests a
longer-lived session. Throws on bad credentials / expired challenge.
restore()
Section titled “restore()”restore(): Promise<AuthUser | null>Validates a persisted session token (from the sessionStore). Returns the user
when valid, or null (clearing a stale token). Does not unlock the identity
— call unlock() for encryption/messaging.
unlock(password)
Section titled “unlock(password)”unlock(password: string): Promise<void>Re-derives the identity for an already-authenticated (restored) session. Verifies the password by matching the derived commitment to the session’s; throws on mismatch.
enrollPasskey(opts?)
Section titled “enrollPasskey(opts?)”enrollPasskey(opts?: { rpId?: string; rpName?: string; label?: string }): Promise<void>Adds a WebAuthn passkey (PRF) that wraps the master seed. Signed-in only.
loginWithPasskey(username, opts?)
Section titled “loginWithPasskey(username, opts?)”loginWithPasskey(username: string, opts?: { rememberMe?: boolean }): Promise<AuthUser>Passwordless sign-in via an enrolled passkey. Unwraps the seed and re-derives the identity, establishing session and identity.
passkeyAvailable()
Section titled “passkeyAvailable()”passkeyAvailable(): booleanWhether WebAuthn is usable in this browser (sync).
passkeyPrfAvailable()
Section titled “passkeyPrfAvailable()”passkeyPrfAvailable(): Promise<boolean | null>Whether the authenticator supports the required PRF extension. null means it
can’t be determined. Gate the passkey UI on a true result.
enrollRecoveryPhrase()
Section titled “enrollRecoveryPhrase()”enrollRecoveryPhrase(): Promise<string>Returns a 24-word BIP39 phrase to display once — it is the seed, nothing is stored server-side. Deterministic, so it returns the same words each call. Signed-in only.
recoverWithPhrase(username, mnemonic)
Section titled “recoverWithPhrase(username, mnemonic)”recoverWithPhrase(username: string, mnemonic: string): Promise<AuthUser>“Forgot password” path: re-derives the identity from the phrase and signs in.
Follow with changePassword() to set a new password.
enrollEmailFactor(email)
Section titled “enrollEmailFactor(email)”enrollEmailFactor(email: string): Promise<{ email: string; confirm: (code: string) => Promise<void>;}>Add an email as a recovery + login factor. Sends a one-time code to the
address and returns a confirm continuation — call it with the code from the
inbox to finish enrolling:
const { confirm } = await client.auth.zk.enrollEmailFactor("me@example.com");await confirm(codeFromInbox);Signed-in only (the seed must be held). Verification-gated: the server only releases the split-key OPRF eval after the address is OTP-verified. Disclose the custody trade-off (recoverability vs. custody) in your enroll UI.
recoverWithEmail(username, opts?)
Section titled “recoverWithEmail(username, opts?)”recoverWithEmail(username: string, opts?: { rememberMe?: boolean }): Promise<{ confirm: (code: string) => Promise<AuthUser>;}>“Forgot password” path via an enrolled email factor. Sends a code to the
stored address (the response never reveals whether one exists), then
confirm(code) unwraps the seed and signs in. Follow with changePassword().
const { confirm } = await client.auth.zk.recoverWithEmail("alice");const user = await confirm(codeFromInbox);enrollGoogleFactor(idToken)
Section titled “enrollGoogleFactor(idToken)”enrollGoogleFactor(idToken: string): Promise<void>Link a Google account as a recovery + login factor. idToken is a fresh Google
ID token obtained via Google Identity Services (the SDK never renders Google UI).
Signed-in only.
loginWithGoogle(username, idToken, opts?)
Section titled “loginWithGoogle(username, idToken, opts?)”loginWithGoogle(username: string, idToken: string, opts?: { rememberMe?: boolean }): Promise<AuthUser>Sign in with Google — verifies the ID token, unlocks the seed via the gated
split-key eval, and establishes session and identity. The account must have
linked the factor first (enrollGoogleFactor). Serves both “Sign in with
Google” and “recover with Google”.
registerWithGoogle(username, idToken)
Section titled “registerWithGoogle(username, idToken)”registerWithGoogle(username: string, idToken: string): Promise<AuthUser>Register a brand-new, passwordless account whose only factor is Google. A random master seed is generated and wrapped under the Google-gated key; the user can add a password / passkey / phrase later. ZK registration is identical to a password signup.
changePassword(newPassword)
Section titled “changePassword(newPassword)”changePassword(newPassword: string): Promise<void>Re-wraps the unchanged seed under a new password. Identity and commitment never move. Signed-in only.
listFactors()
Section titled “listFactors()”listFactors(): Promise<Array<{ id: string; type: "password" | "passkey" | "phrase-marker" | "email" | "google"; label?: string; createdAt?: number; masked?: string;}>>Lists the user’s enrolled login methods (metadata only). Gated factors
(email / google) carry a masked display hint (e.g. "m•••@gmail.com");
the full value is never returned.
removeFactor(id)
Section titled “removeFactor(id)”removeFactor(id: string): Promise<void>Removes an enrolled factor. Throws if it’s the last remaining one.
recover()
Section titled “recover()”recover(): Promise<boolean>Silently re-mints a session token by re-proving the in-memory identity — no
password prompt. Resolves true if it succeeded, false if it can’t (the
identity isn’t in memory, e.g. after a reload that kept only the token). The
client calls this automatically when a request hits 401; you normally use the
client-level recoverSession() +
onSessionExpired instead of calling it
directly.
logout()
Section titled “logout()”logout(): Promise<void>Clears the session, identity, and persisted token.
Getters
Section titled “Getters”| Getter | Type | Description |
|---|---|---|
client.auth.zk.user | AuthUser | null | Current user (sync). |
client.auth.zk.token | string | null | Current session token (sync). |
client.auth.zk.identity | ZkIdentity | null | Derived identity, or null when locked. |
client.auth.zk.seedBase64 | string | null | Master seed as base64, or null when locked. Wrap per-user app data to this so it survives password changes and passkey login. |
client.auth.user | AuthUser | null | Convenience alias. |
Errors
Section titled “Errors”import { VaultUnavailableError } from "@muhkoo/connect";VaultUnavailableError— thrown bylogin/unlockwhen the per-user vault is unreachable (network / 5xx / rate-limit). Distinct from a wrong password — tell the user to retry rather than re-enter credentials.
client.auth.hosted
Section titled “client.auth.hosted”Centralized hosted auth on auth.muhkoo.dev (authorization-code + PKCE). See the
Hosted authentication guide.
login({ appId, redirectUri })—Promise<string>. Stashes a PKCE verifier +stateand redirects the browser to the hosted/authorizepage; resolves to the URL (also returned for popup/test use).redirectUrimust be registered for the app (portal → App Detail → Hosted sign-in).handleCallback()—Promise<{ username, commitment }>. On your callback route: verifiesstate, exchanges the code for a session, unseals the master seed from the URL fragment, establishes the session + identity, and scrubs the URL. Throws on a bad/expired code or PKCE/CSRF mismatch.isCallback()—boolean.truewhen the current URL is a hosted-auth callback (?code&state). Use it to guardhandleCallback().manageAccount({ returnUri? })—Promise<string>. Redirect to centralized account & security management (auth.muhkoo.dev/security), where the user manages passkeys, recovery email, Google, recovery phrase, and password.returnUri(default: the current URL) becomes a “Back to app” button. Wire it to a “Manage account” / settings entry in your app — there’s no per-app security UI to build.
Set authBaseUrl on the Client to override the hosted origin (default
auth.muhkoo.dev).