NewWacht Bench is live — AI-assisted development for Wacht
GuidesOAuth Apps

OAuth Apps for SaaS

End-to-end guide for creating OAuth apps, managing clients, handling consent, and validating tokens with Wacht.

OAuth Apps for SaaS

An OAuth app in Wacht is a self-contained authorization server: its own FQDN, its own RSA signing keys, its own client registry and consent flow. You create one when your SaaS needs to let third parties integrate against your API, or when you want to protect your own resource servers with OAuth tokens. Every OAuth app is also an OpenID Connect provider — same FQDN serves discovery, JWKS, and UserInfo — so "sign in with your product" comes for free.

Unlike API Auth and webhook apps, there's no ticket-and-vanity-UI model here. You define the app and its clients in Console (or the SDK), Wacht runs the authorize/token/consent flow on the app's FQDN, and your resource server verifies the tokens that come out. The work splits into four guides, read in order:

  1. Create OAuth apps and clients
  2. Implement the OAuth consent flow
  3. Verify tokens and operate OAuth clients
  4. Use Wacht as an OpenID Connect provider

Verify tokens in your resource server with the gateway — gateway.checkPrincipalAuthz in Node, gateway().check_authz_with_principal_type in Rust. Secret rotation and grant revocation are scriptable through the same SDK OAuth operations, so you can run scheduled rotation or incident response without the Console.

Two redirects, two owners

The flow has two redirects, and confusing them is the most common setup mistake.

The consent UI redirect is platform-managed. /oauth/authorize redirects to /oauth/consent/init, which lands the user on https://<deployment.frontend_host>/oauth/consent. This path is fixed by your deployment's frontend host. It is not client-configurable — you can't point consent at your own page.

The callback redirect is client-controlled. After the user approves or denies, Wacht redirects back to the OAuth client's redirect_uri, which has to match one of the client's registered redirect_uris exactly. Each client owns its own callback targets.

So: the consent screen is the same for every client on the app (your deployment's frontend host), but where the user lands afterward is per-client.

What you configure

From Console or the backend management API:

  • OAuth app: slug, name, description, logo, supported_scopes, scope_definitions, allow_dynamic_client_registration, is_active.
  • App domain/FQDN: set at creation. Production requires an explicit FQDN; non-production gets an auto-generated <random>.oapi.trywacht.xyz. The slug is baked into the FQDN, so don't rename it after clients are configured.
  • OAuth client: client_auth_method, grant_types, redirect_uris, metadata (client_name, client_uri, logo_uri, tos_uri, policy_uri, contacts, software_id, software_version), key material (jwks_uri, jwks, public_key_pem), token_endpoint_auth_signing_alg.
  • Client lifecycle: deactivate, rotate secret.
  • Grants: list per client, revoke.

Runtime endpoints on each app FQDN

Every OAuth app FQDN serves:

  1. GET /oauth/authorize
  2. POST /oauth/token
  3. POST /oauth/revoke
  4. POST /oauth/introspect
  5. POST /oauth/register and GET|PUT|DELETE /oauth/register/{client_id} — only when dynamic client registration is enabled
  6. GET /.well-known/oauth-authorization-server
  7. GET /.well-known/oauth-protected-resource

Point standards-compliant OAuth and OIDC libraries at the discovery endpoints rather than hardcoding these — they self-configure from .well-known.

  1. Node SDK OAuth apps API
  2. Rust SDK OAuth apps guide
  3. Node SDK gateway authz
  4. Frontend OAuth consent API reference
  5. Backend API reference

On this page