NewWacht Bench is live — AI-assisted development for Wacht
GuidesAPI Auth

API Auth

Customer-managed API keys — lifecycle, audit, analytics, vanity or custom UX.

An API Auth app is the control plane for the API keys your customers issue against your product. One app per deployment holds the key prefix, lifecycle (create, rotate, revoke), per-request audit log, and traffic analytics. Use it for public developer APIs, partner integrations, or any B2B surface where a customer owns their own keys and your support and security teams need to see what those keys did.

The keys themselves are checked at request time through the gateway, the same way OAuth access tokens are. This guide is about the management surface around them — who can mint a key, how the frontend gets permission to render that UI, and what you put on the operator screens.

Create the app first

Nothing else works until the app exists — tickets reference it by slug, and the runtime resolves the key_prefix from it.

import { WachtClient } from "@wacht/backend";

const client = new WachtClient({
  apiKey: process.env.WACHT_BACKEND_API_KEY!,
});

await client.apiKeys.createApiAuthApp({
  app_slug: "aa_42",
  name: "Acme Public API",
  key_prefix: "acme_live",
  description: "API keys for Acme customers",
});

app_slug, name, and key_prefix are required. Convention is aa_<deploymentId> so the slug is derivable rather than looked up. key_prefix is what every issued key starts with (acme_live_…) — pick it before you ship keys, because changing it later doesn't rewrite keys already in the wild. On a non-SDK runtime, POST the same fields directly.

How the frontend gets in

The management UI never holds your backend API key. Your backend is the policy authority; the browser gets a short-lived, app-scoped session and nothing more.

  1. The user signs in to your app.
  2. Your backend confirms tenant ownership and runs your own RBAC for key management — Wacht doesn't decide who's allowed to mint keys, you do.
  3. Your backend issues a ticket with ticket_type=api_auth_access and api_auth_app_slug set to this app. Without the slug the ticket request is rejected.
  4. The frontend exchanges it at /session/ticket/exchange and calls /api-auth/* with the resulting session.

Tickets default to a 12-hour TTL. Issue them on demand behind your RBAC gate rather than minting long-lived ones — a leaked ticket only grants what this one app exposes, and only until it expires. This same ticket-issuance pattern is what gates webhook apps; the difference here is the ticket type and the slug.

Vanity surface or your own UI

Two ways to render the management UX, both sitting behind the same ticket:

Vanity pages are a hosted management surface you hand the user into with a ticket. You get key lifecycle, audit, and analytics screens without building them. Reach for this when you want keys shipped now, or when you're still learning how your API customers behave and don't want to commit frontend code to a workflow that may change. See vanity pages implementation.

Custom hooks (useApiAuthAppSession, useApiAuthKeys, the audit hooks) let you build key management inside your existing settings pages. Reach for this when key management is a core workflow with its own IA, when you need approval gates or policy that the hosted UI doesn't model, or when the experience has to match the rest of your product. See custom hook implementation.

You can start on vanity and move specific flows to custom later — the trust boundary and the ticket are identical, so only the rendering changes.

Decide these before you build

These are product decisions Wacht won't make for you, and each one changes the UI:

  • Key scope. User, org, or workspace. Determines what the create form asks for and what audit rows mean.
  • Expiry. Optional or mandatory. If mandatory, the create form needs an expiry field and the audit screen needs an expired-vs-revoked distinction.
  • Rotation. Manual only, or a required cadence you enforce in your own backend.
  • Revocation authority. Owner-only, or admin override. This is RBAC at ticket-issuance time, not a Wacht setting.

Lock the audit requirement too: whatever your support and security teams need to see drives the observability screens, so design those screens against real questions ("which key sent the blocked traffic at 0200") not generic charts.

  1. API Auth vanity implementation
  2. API Auth custom hook implementation
  3. Building API Auth observability screens
  4. React Router useApiAuthAppSession / useApiAuthKeys
  5. Node SDK API Keys API
  6. Backend API reference

On this page