Guide · not normative
The Focus AI Standards
Guide: GDE-002
Status: Current
Relates to: STD-009
W. Schenk
The Focus AI
2026-07-25
Verified 2026-07-25

Clerk authentication setup

Status of this guide

This is a guide: explanation, walkthrough and reference implementation. It contains no clauses and binds nothing (STD-001 §4). The rules in this area are STD-009; where this document and a standard disagree, the standard is the authority.

When a guide turns out to contain a rule, the rule moves to a standard where it can be cited and checked, and the guide keeps the explanation.

Rules extracted to STD-009; this is the per-provider walkthrough.

Clerk is the default auth layer (see best-practices/GDE-009-technology-defaults.md). These rules cover how to set it up across multiple client projects that live on subdomains of one root domain (e.g. thp.thefocus.ai, habitats.thefocus.ai).

One Clerk application per client

Always run a production instance in production

``bash echo "${NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY#pk_live_}" | base64 -d # → clerk.thp.thefocus.ai (a *.clerk.accounts.dev result means it's a DEV instance) ``

Per-client production setup (repeat for each client)

  1. Create the application, then Create production instance (clone dev — note SSO connections, integrations, and Paths do NOT copy and must be re-added).
  2. Set the instance domain to the client subdomain, e.g. thp.thefocus.ai.
  3. Add the CNAME records from the Clerk Domains page. Standard set (hosts shown relative to the thefocus.ai zone, for the thp subdomain):

``text clerk.thp CNAME frontend-api.clerk.services # Frontend API accounts.thp CNAME accounts.clerk.services # Account Portal clkmail.thp CNAME mail.<token>.clerk.services # email clk._domainkey.thp CNAME dkim1.<token>.clerk.services # DKIM clk2._domainkey.thp CNAME dkim2.<token>.clerk.services # DKIM ``

  1. Cloudflare: set every Clerk record to "DNS only" (grey cloud). A proxied (orange-cloud) record fails Clerk's domain/SSL verification.
  2. Put pk_live_… / sk_live_… in that client's hosting env (each client is its own Vercel project). The #1 prod mistake is forgetting to swap the keys.
  3. Add your own social OAuth credentials (see "Social OAuth" below) and re-point webhooks to the production instance.
  4. Lock origins in middleware so a token from one client is rejected by another:

``ts // middleware.ts (per project) import { clerkMiddleware } from "@clerk/nextjs/server"; export default clerkMiddleware({ authorizedParties: ["https://thp.thefocus.ai"] }); ``

  1. Deploy certificates in the Dashboard (DNS can take up to 48h to propagate).

Social OAuth (Google + Microsoft)

Development instances use Clerk's _shared_ OAuth credentials, so social login "just works" in dev. Production instances require your own credentials — any social button that worked in dev breaks in prod until you add them.

Each Clerk production instance has one redirect URI, tied to its Frontend API domain. Copy the exact value from the Clerk Dashboard (SSO Connections → provider → _Use custom credentials_); it looks like:

https://clerk.thp.thefocus.ai/v1/oauth_callback        # THP instance
https://clerk.habitats.thefocus.ai/v1/oauth_callback   # Habitats instance

One shared OAuth app per provider (standard)

Because every client lives under thefocus.ai, use one Google app and one Microsoft app for all clients, each listing multiple redirect URIs (one per Clerk instance). Paste the same Client ID/Secret into each client's Clerk instance.

Google setup (per provider, once)

  1. Clerk Dashboard → SSO Connections → Google → enable + Use custom credentials → copy the Redirect URI.
  2. Google Cloud Console → OAuth consent screen: External; set the app name (shown to users); Authorized domains = thefocus.ai (covers all subdomains); publish to "In production" (Testing mode caps at 100 users).
  3. Credentials → OAuth client ID → Web application:
  4. Authorized JavaScript origins: https://thp.thefocus.ai (add each client origin).
  5. Authorized redirect URIs: add the Clerk Redirect URI for each instance.
  6. Paste Client ID + Secret into each client's Clerk instance.

Microsoft / Entra ID setup (per provider, once)

  1. Clerk Dashboard → SSO Connections → Microsoft → enable + Use custom credentials → copy the Redirect URI.
  2. Azure → Microsoft Entra ID → App registrations → New registration:
  3. Supported account types: "Accounts in any organizational directory (multitenant) and personal Microsoft accounts." Required so external orgs (e.g. a client's tenant) can sign in. Clerk uses the common tenant.
  4. Redirect URI: platform Web, add the Clerk Redirect URI for each instance.
  5. Certificates & secrets → New client secret → copy the Value. Note the expiry (≤24mo) and set a rotation reminder — expired secrets silently break Microsoft login.
  6. Token configuration: add the email optional claim.
  7. Paste Application (client) ID + secret Value into each client's Clerk instance.

Access control per client

Anti-patterns