Kizaki
ReferenceTypeScript

Auth

Browser and React authentication helpers from @kizaki/sdk.

Browser-side helpers for login, signup, logout, session management, and OAuth. Calls the platform's /__auth/* JSON API. Sessions are HttpOnly cookies — no tokens are exposed to JavaScript.

The auth model is declared in Inspire via auth {}. The platform compiles that config into the app artifact and exposes the /__auth/* endpoints.

Import Paths

// Browser helpers (vanilla JS / any framework)
import { login, logout, getSession, getAuthConfig } from '@kizaki/sdk/auth';

// React hooks and components
import { useAuth, AuthGate } from '@kizaki/sdk/auth/react';

// Also re-exported from the browser entry point
import { login, logout } from '@kizaki/sdk/browser';

Browser API

login(credentials)

Log in with email and password. Sets a session cookie on success.

const { user } = await login({ email: 'alice@example.com', password: '...' });
// user: { id, email, name }

Throws AuthError with code: "invalid_credentials" on bad credentials. Throws AuthError with code: "email_not_verified" until the verification link is used.

signup(credentials)

Create an account. Provide either name or firstName/lastName. Returns { user: null } until email verification is completed.

const { user } = await signup({
  email: 'alice@example.com',
  password: '...',
  name: 'Alice Smith',
});
// user === null until the email verification link is used

Throws AuthError with code: "account_exists" if the email is taken. Throws AuthError with code: "verification_unavailable" if verification email delivery fails; no account is created.

logout()

Clear the session cookie.

await logout();

getSession()

Check the current session. Returns { user: null } if not authenticated.

const session = await getSession();
if (session.user) {
  console.log(session.user.email);
}

getAuthConfig()

Load the server-declared auth configuration for the current app. Use this to render only the providers and linking UI that the compiled auth {} block actually enables.

const auth = await getAuthConfig();

if (auth.providers.includes('google')) {
  loginWithGoogle('/dashboard');
}

refreshSession()

Force-refresh the session token.

const session = await refreshSession();

loginWithGoogle(returnTo?)

Start a Google OAuth flow. Navigates the browser away. The user returns to returnTo (default: current page) after authenticating.

loginWithGoogle('/dashboard');

loginWithGithub(returnTo?)

Start a GitHub OAuth flow. Same pattern as Google.

loginWithGithub();

loginWithProvider(provider, returnTo?)

Start an OAuth flow for any supported provider.

loginWithProvider('google', '/dashboard');

Only call provider-specific helpers for providers returned by getAuthConfig().

onAuthStateChange(listener)

Subscribe to auth state changes. Returns an unsubscribe function.

const unsub = onAuthStateChange((session) => {
  console.log(session.user ? 'in' : 'out');
});

// later
unsub();

getSessionSync()

Return the last known session without a network request.

const session = getSessionSync();

forgotPassword(email)

Request a password reset. Always resolves — the server never reveals whether the email is registered.

await forgotPassword('alice@example.com');

resetPassword(userId, code, newPassword)

Set a new password using a reset code from the password reset email.

await resetPassword(userId, code, 'newSecurePassword');

listAuthMethods()

List authentication methods linked to the current account. Requires an active session.

const methods = await listAuthMethods();
// [{ type: "password" }, { type: "oauth", provider: "google", idpId: "...", externalUserId: "...", displayName: "alice@gmail.com" }]

linkPassword(password)

Add a password to an OAuth-only account. Requires an active session.

await linkPassword('newSecurePassword');

High-risk account change. Handle AuthError with code: "reauth_required" by prompting re-authentication.

linkProvider(provider, returnTo?)

Start an OAuth provider linking flow. Navigates to the OAuth authorize endpoint. After authentication, the account is linked and the user is redirected to returnTo.

linkProvider('github', '/settings/account');

Requires a recent session. Stale sessions fail with reauth_required.

unlinkMethod(method)

Remove an authentication method. Only OAuth methods can be unlinked. Throws last_method if this is the user's only remaining method.

const methods = await listAuthMethods();
const github = methods.find(m => m.provider === 'github');
if (github) await unlinkMethod(github);

Also a recent-auth operation. Expect AuthError with code: "reauth_required" on stale sessions.

AuthError

Error thrown by auth operations.

try {
  await login({ email, password });
} catch (e) {
  if (e instanceof AuthError) {
    console.log(e.code);   // "invalid_credentials"
    console.log(e.status);  // 401
  }
}

Common codes: invalid_credentials, email_not_verified, verification_unavailable, reauth_required, last_method.

React API

Requires React 18+ as a peer dependency.

useAuth()

Manages auth state. Fetches the session on mount and subscribes to changes.

function LoginPage() {
  const { user, loading, error, login, loginWithGoogle, logout } = useAuth();

  if (loading) return <p>Loading...</p>;
  if (user) return <p>Hello {user.name} <button onClick={logout}>Log out</button></p>;

  return (
    <>
      <button onClick={() => login({ email: '...', password: '...' })}>Log in</button>
      <button onClick={() => loginWithGoogle()}>Google</button>
      {error && <p>{error}</p>}
    </>
  );
}

Returns:

FieldTypeDescription
userAuthUser | nullCurrent user or null
loadingbooleanTrue while an auth operation is in flight
errorstring | nullError code from last failed operation
login(creds) => PromiseEmail/password login
signup(creds) => PromiseCreate account and login
logout() => PromiseClear session
refresh() => PromiseForce token refresh
loginWithGoogle(returnTo?) => voidGoogle OAuth redirect
loginWithGithub(returnTo?) => voidGitHub OAuth redirect
loginWithProvider(provider, returnTo?) => voidAny OAuth redirect

AuthGate

Renders children when authenticated, fallback when not.

<AuthGate
  fallback={<LoginPage />}
  loading={<Spinner />}
>
  <Dashboard />
</AuthGate>

Props:

PropTypeDescription
childrenReactNodeShown when authenticated
fallbackReactNodeShown when not authenticated
loadingReactNodeShown while checking session (default: null)

Types

interface AuthUser {
  id: string;
  email: string;
  name: string;
}

interface AuthSession {
  user: AuthUser | null;
}

interface LoginCredentials {
  email: string;
  password: string;
}

interface SignupCredentials {
  email: string;
  password: string;
  firstName?: string;
  lastName?: string;
  name?: string;
}

type AuthProvider = 'email' | OAuthProvider;
type OAuthProvider = 'google' | 'github';
type AuthLinkingMode = 'manual' | 'disabled';
type AuthStateListener = (session: AuthSession) => void;

interface AuthConfig {
  providers: AuthProvider[];
  oauthProviders: OAuthProvider[];
  linking: AuthLinkingMode;
  sessionDurationSeconds: number;
}

interface AuthMethod {
  type: 'password' | 'oauth';
  provider?: string;        // "google" | "github" (only for oauth)
  idpId?: string;           // needed for unlinkMethod
  externalUserId?: string;  // needed for unlinkMethod
  displayName?: string;
}

Error Codes

CodeStatusMeaning
invalid_credentials401Wrong email or password
email_not_verified403Account must complete email verification first
account_exists409Email already registered (signup)
invalid_signup400Signup data failed validation
verification_unavailable503Verification email could not be issued; signup failed closed
auth_not_configured503App has no auth block or provisioning is incomplete
auth_provider_unavailable503Identity provider is unreachable
provider_not_enabled403The requested provider is not declared in auth {}
missing_field400Required field not provided
invalid_json400Request body is not valid JSON
body_too_large413Request body exceeds 1 MB
no_session401No session cookie present
no_refresh_token401Session has no refresh token
refresh_failed401Token refresh was rejected
oauth_failed400OAuth provider returned an error
invalid_state400OAuth state parameter mismatch (possible CSRF)
missing_flow_state400OAuth flow cookie missing or expired
linking_disabled403Account linking is disabled in the schema
last_method400Cannot remove last authentication method
session_mismatch403Session changed during OAuth linking flow

Session Isolation

Each deployed app has its own session secret, generated during kizaki deploy and stored in Vault. Sessions are encrypted with AES-256-GCM using per-app keys.

  • Sessions cannot be shared or reused across apps
  • A session cookie from App A is meaningless to App B
  • Compromising one app's secret does not affect others

How It Works

The auth module does not handle tokens directly. All auth state is managed via HttpOnly cookies:

  1. login() calls POST /__auth/login — the server validates credentials, sets a sealed session cookie, and returns the user
  2. getAuthConfig() calls GET /__auth/config — the server returns the compiled provider/linking/session settings for the current app
  3. loginWithGoogle() navigates to GET /__auth/google — the server redirects through the OAuth flow, then sets a session cookie on callback
  4. Subsequent API requests include the cookie automatically. The platform validates it and injects principal headers before forwarding to the runtime
  5. logout() calls POST /__auth/logout — the server clears the cookie

The identity provider is never visible to the end user.

On this page