Client

Auth

createClient({ auth }) → api.auth — cookie-first, authorize/Can UI-only, Gate remains real authz.

createClient(url, { auth }) attaches api.auth — session orchestration over the same /auth/* Flows. Prefer that one call. createAuthClient + bind stays as a compose escape hatch.

For storefronts and SPAs attaching identity to typed calls.

The one rule

Gate on Flows is real authorization. authorize / hasScope / Can are UI-only. Cookie mode needs the csrf plugin (server soft-requires it when gate.auth.cookies.enabled); never persist tokens to Storage when cookies own the session.

Smallest Example

One createClient with session auth

web/src/api.ts
import { createClient } from "okengine/client";
import { vault } from "okengine/vault";
import { app } from "../../src/app";

export const api = createClient(app, vault.env("PUBLIC_API_URL") ?? "", {
  auth: { mode: "cookie", csrfConfigured: true },
});

api.auth is an AuthClient. Unit Flows remain reachable (api.auth.me, …) under the same namespace.

Sign in and authorize chrome

const result = await api.auth.signIn.email({ email: "alex@acme.co", password });
if (!result.ok) {
  if (result.twoFactor) {
    await api.auth.completeChallenge({
      challengeId: result.twoFactor.challengeId,
      code: totp,
    });
  }
  return;
}

const gate = api.auth.authorize({ all: ["orders:write"] });
if (gate.status === "allowed") showFulfillment();
await api.auth.signOut();

Progressive Patterns

const gate = api.auth.authorize({ all: ["orders:write"] });
// or: api.auth.authorize({ any: ["orders:write", "admin"] })

if (gate.status === "unauthenticated") redirectToSignIn();
if (gate.status === "loading") return;
if (gate.status === "denied") showMissing(gate.missing);
// gate.status === "allowed"

React: <Can auth={api.auth} all={["orders:write"]} fallback={<Denied />}>. Prefer authorize / Can over bare hasScope. On server Forbidden, use isForbidden / forbiddenScopes and refresh getSession() if scopes look stale.

Helpers

HelperPackageRole
createClient({ auth })okengine/clientHappy path — attaches api.auth
createAuthClientokengine/client/authCompose / bind escape hatch
tokenFromRequestCookies / createServerClientsameSSR cookie → token
authorize / hasScope / canon AuthClientUI-only chrome
isUnauthorized / isCsrf / forbiddenScopessameEnvelope narrowers
useSession / useAuthorize / Canokengine/client-reactReact session + chrome

Denial codes

CodeHTTPTypical fix
Unauthorized401Sign in or refresh; re-login if still denied
Forbidden403Wrong scopes / CSRF — read error.data.reason
RateLimited429Wait retryAfterMs

Also see CORS and CSRF. Advanced create-oke starter demos cookie + passkey + <Can>.

Troubleshooting

Learn more

  • Calling — envelopes, binary { response: "blob" }, REST
  • ReactuseSession / Can / useAuthorize
  • Gate · Auth — server cookies and scopes

Next

On this page