@kiavi/kiavi-browser
Ce contenu n’est pas encore disponible dans votre langue.
0.3.1Browser SDK for Kiavi-hosted authentication. Use this in any frontend (React, Vue, Svelte, plain JS) when you need to sign users in against a Kiavi auth server and attach their access token to outgoing API calls.
This page mirrors the llm-docs.md that ships with the installed package, that file is the authoritative source. If anything here ever drifts, trust the package version.
Install
Section titled “Install”pnpm add @kiavi/kiavi-browser(Or npm install, yarn add, bun add, they all work.)
Then run the init command to install the version-pinned integration guide for AI coding agents into your repo:
npx kiavi-browser initThis writes .kiavi/kiavi-browser.md and adds a reference block to your AGENTS.md (or CLAUDE.md). Re-run on every upgrade. See AI agent docs for the full explanation.
Minimum viable integration
Section titled “Minimum viable integration”Three things, in order:
- Create one
KiaviClientinstance and export it. - Call
authenticate()at app startup (or inside a route guard) to ensure the user is signed in. This redirects to the hosted login page if not. - Call
getAccessToken()before each API call and attach it as aBearertoken.
import { KiaviClient } from '@kiavi/kiavi-browser'
export const auth = new KiaviClient('https://auth.your-domain.com')// app entry / root route loaderimport { auth } from './lib/auth'
const session = await auth.authenticate()// If there's no session, authenticate() has already triggered a full-page// redirect and this line is never reached. No need for null checks.// any API callimport { auth } from './lib/auth'
const token = await auth.getAccessToken()const res = await fetch('/api/things', { headers: { Authorization: `Bearer ${token}` },})// sign out buttonimport { auth } from './lib/auth'
await auth.signOut() // clears local state and redirects to the hosted signout pageThat is the full happy path. Do not implement anything beyond this unless you have a reason.
Options
Section titled “Options”new KiaviClient('https://auth.your-domain.com', { clientId: 'my-app', locale: 'en', authPolicy: 'passkey_preferred', debug: true,})clientId?: string, OIDC client ID. Required for exchange-mode auth servers (cross-origin deployments, the most common case); unused in cookie mode. The client picks the right flow automatically from/.well-known/kiavi-auth.json. A missingclientIdin exchange mode surfaces as an error fromauthenticate()when the redirect is built.locale?: string, passed aslang(andui_localeswhere applicable) on hosted-page redirects.authPolicy?: 'passkey_required' | 'passkey_preferred', override the policy advertised by the server. Most callers should leave this unset and letgetAuthPolicy()read it from the server.debug?: boolean | KiaviDebugLogger,trueenables the built-in console logger with sensitive fields redacted. A function receives structuredKiaviDebugLogEntryobjects so you can route logs into your own observability tooling.
Methods you will use
Section titled “Methods you will use”authenticate(options?): Promise<KiaviSession>
Section titled “authenticate(options?): Promise<KiaviSession>”Ensure a session exists. Resolves with the live session if one is already present, silently refreshable, or recovered from a ?code=&state= callback the constructor saw on page load. Otherwise redirects to login and the returned promise never resolves.
Call once at app/route entry. options.returnTo controls where the user lands after sign-in (defaults to the current URL minus any stale code params). options.replace: true uses location.replace instead of assignment.
getAccessToken(): Promise<string>
Section titled “getAccessToken(): Promise<string>”Returns a valid JWT, refreshing silently if needed. Call it on every API request. Do not cache the result, it’s cheap and refresh is automatic.
Throws KiaviSessionExpiredError if the session can’t be recovered; catch that and call authenticate() to kick off the redirect flow.
signOut(options?): Promise<void>
Section titled “signOut(options?): Promise<void>”Clears local state, revokes server-side (fire-and-forget), and (by default) redirects to the hosted signout page. options.returnTo controls where the browser lands after sign-out (defaults to the current origin). Pass { redirect: false } to clear local state without navigating.
getSession(): Promise<KiaviSession | null>
Section titled “getSession(): Promise<KiaviSession | null>”Non-redirecting read of the current session. Awaits any in-flight code exchange, then attempts one silent refresh. Returns null if the user is not signed in. Use this when you need to check for a session without triggering a redirect (e.g. to render a signed-out landing view). Safe to call on the server: returns null without throwing.
onAuthStateChange(listener): () => void
Section titled “onAuthStateChange(listener): () => void”Subscribe to session changes. Fires on every successful authenticate/refresh, every sign-out, and every failed refresh that clears the session. Does not fire synchronously on subscription, call getSession() first if you need the current state. Returns an unsubscribe function.
Methods you will rarely need
Section titled “Methods you will rarely need”getAuthPolicy(), returns'passkey_required'or'passkey_preferred'for UI that adapts to the configured policy.getProfile(): Promise<KiaviProfile | null>, returns the authenticated user’s social profile snapshot ({ name, picture, provider }) captured by the IdP at sign-in time. Returnsnullwhen the user is unauthenticated or signed in without a social provider (passkey-only, email-code-only). Kiavi does not refresh this data , call the provider’s API yourself if you need fresh values. ThrowsKiaviAuthErroron non-2xx responses other than 401 (which surfaces asnull).setLocale(locale)/setDebugLogger(debug), update configuration at runtime.
Email verification and change email
Section titled “Email verification and change email”Two account-management methods let you trigger email flows directly from your app. Both resolve to void on success and throw KiaviAuthError on any non-2xx response.
resendVerificationEmail({ email, callbackURL? })
Section titled “resendVerificationEmail({ email, callbackURL? })”Unauthenticated, call this when a user reports they didn’t receive their verification email. The server responds with 200 regardless of whether the email exists (to avoid leaking account existence), so treat a resolved promise as “request accepted”, not as “email definitely sent”.
try { await auth.resendVerificationEmail({ email: 'user@example.com', callbackURL: window.location.href, }) showToast('If we know that email, a verification link is on its way.')} catch (err) { if (err instanceof KiaviAuthError && err.code === 'rate_limited') { showToast(`Please wait ${err.retryAfterSeconds ?? 30}s before trying again.`) } else { showToast('Something went wrong. Please try again.') }}changeEmail({ newEmail, callbackURL? })
Section titled “changeEmail({ newEmail, callbackURL? })”Requires an active session. The request is authenticated via the auth server’s session cookie (sent automatically with credentials: 'include').
The server’s behavior depends on whether the current email is verified:
- Verified current email → A confirmation email is sent to the current address. The email only actually changes after the user clicks the link.
- Unverified current email (if the auth server allows it) → The email is updated immediately and a verification email is sent to the new address.
Either way, the promise resolves to void and you should tell the user “check your inbox”.
try { await auth.changeEmail({ newEmail: 'new@example.com', callbackURL: window.location.href, }) showToast('Check your inbox to confirm the change.')} catch (err) { if (err instanceof KiaviAuthError) { showToast(err.message) }}Errors
Section titled “Errors”KiaviAuthError
Section titled “KiaviAuthError”Thrown by resendVerificationEmail, changeEmail, and getProfile on failure. Fields:
code: KiaviAuthErrorCode,'rate_limited' | 'invalid_request' | 'unauthenticated' | 'server_error' | 'network_error' | 'unknown'status: number, HTTP status, or0for network errors / invalid inputretryAfterSeconds?: number, parsed from theRetry-Afterheader on 429 responsesmessage: string, server-provided message when available, otherwise a generic description
KiaviSessionExpiredError
Section titled “KiaviSessionExpiredError”Thrown by getAccessToken() when the session can’t be recovered. Catch and call authenticate() to start a new sign-in flow.
KiaviBrowserOnlyError
Section titled “KiaviBrowserOnlyError”Thrown when a browser-only method is called during SSR. Use getSession() (which is SSR-safe) instead.
Exported from @kiavi/kiavi-browser:
KiaviClient, the class aboveKiaviSession,{ token: string, expiresAt: number | null, user: KiaviSessionUser | null }KiaviSessionUser,{ id: string, email: string, emailVerified?: boolean, phone?: string, phoneVerified?: boolean, name: string | null }KiaviProfile,{ name: string | null, picture: string | null, provider: string }, returned bygetProfile()KiaviAuthPolicy,'passkey_required' | 'passkey_preferred'KiaviClientOptions,KiaviAuthenticateOptions,KiaviSignOutOptionsKiaviAuthStateListener,(session: KiaviSession | null) => voidKiaviSessionExpiredError,KiaviBrowserOnlyErrorKiaviAuthError,KiaviAuthErrorCodeKiaviResendVerificationEmailOptions,KiaviChangeEmailOptionsKiaviDebugLogger,KiaviDebugLogEntry
Do / do not
Section titled “Do / do not”Do:
- Create exactly one
KiaviClientinstance per app and export it as a module singleton. - Call
authenticate()once at the top of your app or inside a route guard, then trust that the session exists. - Call
getAccessToken()inline on every API call, it’s fast and handles refresh. - Pair this with
@kiavi/kiavi-json your backend to verify the JWTs this client produces.
Do not:
- Do not manually parse
?code=...&state=...from the URL. The client handles it automatically in the constructor. - Do not cache or store the return value of
getAccessToken()beyond the scope of a single request, tokens are short-lived and the client refreshes them for you. - Do not implement your own refresh loop, interval, or retry wrapper around
getAccessToken(). It is already silent and automatic. - Do not write tokens to
localStorageor cookies yourself. The client owns session storage. - Do not call
authenticate()in a loop, call it once at entry, then usegetAccessToken()for API calls andgetSession()for non-redirecting reads.