Clerk Knowledge Patch
Use this guide when implementing, upgrading, or debugging Clerk authentication,
authorization, Organizations, Billing, SDKs, components, or deployment architecture. Start with the migration notes, then open the matching reference.
Reference index
| Reference |
Topics |
| Architecture and deployment |
Account Portal, FAPI, cookies, handshake, environments, routing, Astro, Next.js, Dashboard roles, Platform API |
| Authentication and sessions |
Factors, SSO, OAuth/OIDC, passkeys, pending sessions, reverification, JWT claims, restrictions |
| Billing |
Plans, Features, Subscriptions, trials, checkout, discounts, hooks, administration |
| Components |
Sign-in-or-up, Waitlist, Google One Tap, Show, loading controls, redirects, Billing drawers |
| Core 3 migration |
Signal API, Expo native UI and hooks, attempt errors, MFA, transfer handling |
| Customization |
Appearance, themes, Tailwind, iOS theming, localization, templates, Elements, profile extensions |
| Frontend resources |
Browser API keys, Web3, email links, token cache, user refresh, listeners, multi-session behavior |
| Go Backend SDK |
v2 setup, clients, middleware, resources, JWTs, roles, machines, settings |
| Integrations and webhooks |
Svix webhooks, Inngest, framework middleware, MCP, FAPI proxies, satellites, Chrome extensions |
| JavaScript Backend SDK |
Request authentication, Next.js token types, user migration, metadata, JWT templates, API keys |
| Organizations and enterprise |
Tenant scoping, roles, permissions, role sets, invitations, Verified Domains, enterprise connections |
| Python Backend SDK |
Authentication, retries, API keys, agent tasks, Billing, machines, releases and breaking schemas |
Breaking migrations and changed defaults
Migrate custom flows to Core 3
Core 3 uses named factor methods and explicit finalization. Do not port old
attemptFirstFactor() or createdSessionId activation literally.
const { signIn } = useSignIn()
await signIn.create({ identifier: email })
await signIn.password({ password })
if (signIn.status === 'complete') {
await signIn.finalize({ navigate: () => router.push('/') })
}
- Email-code sign-in uses
signIn.emailCode.sendCode() and verifyCode().
- Sign-up verification lives under
signUp.verifications.
- MFA uses the
signIn.mfa namespace.
- Read field failures from
errors.fields, other handled failures from
errors.global, and unparsed failures from errors.raw.
- Attempt objects change identity as a flow advances; include the attempt
object in React dependency arrays.
- Use
clerk.setActive() for an existingSession; use an attempt's
finalize() for a newly completed attempt.
Treat pending sessions as unauthenticated by default
Organization selection, forced-password reset, or required-MFA setup can leave a session pending. IDs are normally null and protected routes reject it.
After finalization, inspect session.currentTask and route to the task UI. Use treatPendingAsSignedOut: false only where pending identity is intentional.
Update request-authentication checks
JavaScript authenticateRequest() reports isAuthenticated; isSignedIn is deprecated. The result distinguishes signed-in, signed-out, and handshake, exposes tokenType, and converts through toAuth().
const state = await client.authenticateRequest(request, {
authorizedParties: ['https://app.example.com'],
})
if (!state.isAuthenticated) return new Response('Unauthorized', { status: 401 })
Next.js auth() accepts session tokens by default. Explicitly set
acceptsToken for API keys, OAuth tokens, or mixed machine routes, then branch
on tokenType and scopes.
Account for SDK and prop migrations
- Python 5.x generated schemas can change incompatibly even in patch or minor releases. Pin exact versions and inspect request/response changes; 6.0.0 changes
users.update() and organizations.update() inputs.
- Go v2 requires Go 1.24+ and imports from
github.com/clerk/clerk-sdk-go/v2.
<SignOutButton> takes redirectUrl and sessionId directly; signOutOptions is deprecated.
- Move
<UserButton> sign-out destinations to <ClerkProvider>; only afterSwitchSessionUrl stays local.
satelliteAutoSync defaults to false; explicitly enable automatic synchronization.
- Use
CLERK_JS_URL, not CLERK_JS; replace old after-sign-in/up variables with fallback or force redirect settings.
- Replace
sessions.verifySession() with full-request authentication or direct JWT validation.
- Import extension background clients from
@clerk/chrome-extension/client with background: true.
- Move enterprise administration from
/saml_connections to /v1/enterprise_connections.
Rename appearance variables
Prepare for removal of these deprecated names:
| Old |
Current |
colorText |
colorForeground |
colorTextOnPrimaryBackground |
colorPrimaryForeground |
colorTextSecondary |
colorMutedForeground |
spacingUnit |
spacing |
colorInputText |
colorInputForeground |
colorInputBackground |
colorInput |
Authentication quick reference
Enumeration-safe combined sign-in and sign-up
Use signIn.create({ identifier, signUpIfMissing: true }). Verification
returns sign_up_if_missing_transfer for a new account, after which
signUp.create({ transfer: true }) preserves the verified identifier. This
excludes password, username, restricted, and waitlist flows. The embedded
combined flow can also perform this verification-first behavior under strict
enumeration protection when the instance is open-access and starts without a
password.
Reverification
Server code checks auth.has({ reverification: preset }) and returns
reverificationError(preset); client code wraps the operation with
useReverification(). If the user lacks a second factor, a requested second-
or multi-factor level downgrades to first-factor verification. Native Expo
must provide onNeedsReverification; the prebuilt modal is web-only.
Session-token claims
Current session tokens include v, pla, fea, sts, and an o object only
when an Organization is active. Keep custom claims below 1.2 KB so the complete
cookie stays below browser limits. Use CLERK_JWT_KEY or a supplied jwtKey
for networkless verification.
OAuth and machine tokens
- Clerk exposes OAuth/OIDC discovery, token, user-info, and token-info
endpoints.
- Dynamic client registration is public and forces the consent screen on.
- API routes must opt into
oauth_token; API-key routes must opt into
api_key.
- M2M creation supports locally verifiable JWTs or immediately revocable
opaque tokens.
- A custom JWT template is independent of a session and cannot include
session-bound
sid, v, pla, or fea.
Framework and deployment quick reference
Next.js
Calling server-side auth() makes the route dynamic. Client useAuth() stays
static by default; scope <ClerkProvider dynamic> narrowly, optionally under
<Suspense>. Built-in FAPI proxying is available through clerkMiddleware()
or App Router proxy handlers.
Astro
Endpoints use synchronous locals.auth(), await locals.currentUser(), and
clerkClient(context). Never serialize the complete Backend User because it
contains privateMetadata. Match isStatic on Clerk controls to whether the
page is prerendered.
Production sessions
The long-lived __client JWT on the FAPI domain is distinct from the one-minute
__session JWT on the exact application domain. Cross-subdomain APIs should
receive the session token in Authorization. An expired server-rendered token
can trigger a 307 FAPI handshake; preserve Clerk's context headers through
adapters and proxies.
Environment topology
Development instances have a 100-user cap and cannot transfer users to
production. Staging normally needs a separate application and domain. A preview
sharing production identity must use production keys on a subdomain of the
same root domain; provider-owned preview domains use development keys.
Organizations and authorization quick reference
- Store the Organization ID on tenant-owned records and verify it on every
query.
- Active Organization is tab-local, but the shared cookie can reflect another
active tab. Fetch a token in the current tab and send it as a bearer token for
tenant-scoped background work.
- An unknown or unauthorized slug leaves the prior Organization active.
Compare route
slug with authenticated orgSlug before reading tenant data.
- System Permissions are not session claims. Use equivalent Custom Permissions
for server-side
has() checks.
- A Custom Permission succeeds only while the active Organization Plan includes
its corresponding Feature.
- Role Set changes propagate to assigned Organizations; switching or deleting
sets requires explicit Role remapping.
- Organization collection hooks fetch nothing unless each collection is
requested.
Billing quick reference
Clerk Billing objects are separate from Stripe Billing objects. The service is
USD-only and has no native refunds, tax/VAT calculation, 3D Secure confirmation,
or merchant-of-record service. Authorize entitlements with has() or <Show>,
not display hooks.
For custom checkout, call start(), confirm(), then finalize() to
synchronize identity state. New cards require <PaymentElementProvider> and
<PaymentElement />; existing cards pass paymentMethodId. Billing buttons
must be inside <Show when="signed-in">, and Organization checkout also
requires an Active Organization.
UI and customization quick reference
<Show> accepts roles, permissions, features, plans, or a callback, but only
hides client content; repeat sensitive checks on the server.
<GoogleOneTap> needs custom Google credentials and does not return provider
access tokens.
- Embedded
<Waitlist /> needs Waitlist mode plus waitlistUrl.
- Global appearance supports
theme, options, variables, elements,
captcha, and cssLayerName; direct component appearance wins for one
instance.
- For Tailwind v4, place Clerk in an earlier cascade layer than
utilities.
- Stable DOM hooks are the human-readable
cl-* classes before the lock marker;
remove cl- when using an appearance.elements key.
- Hosted Account Portal pages allow Dashboard customization only; prebuilt
components allow CSS changes; Elements allows custom HTML/CSS but still owns
flow order; only API-built flows control authentication logic.
Native Expo quick reference
@clerk/expo 3.1 requires Expo SDK 53+. Its config plugin installs native iOS
and Android dependencies. AuthView, UserButton, and UserProfileView come
from @clerk/expo/native; native Google sign-in uses platform-native APIs. Set
the plugin's appleSignIn option to false when the entitlement is not needed.
Use useUserProfileModal(), useNativeSession(), and useNativeAuthEvents()
for native state. Trusted-device APIs can enroll a device for later biometric
sign-in. Cloudflare bot protection is unsupported in Expo and must be disabled
there.
Before shipping
- Confirm accepted token types and authorized parties for every backend route.
- Enforce tenant and entitlement checks on the server, even when UI controls
hide content.
- Handle handshake, pending-session, and reverification states explicitly.
- Check redirect URLs, Account Portal return targets, proxy headers, and
satellite origins.
- Capture API-key secrets and OAuth client secrets at creation; they are not
generally retrievable later.
- Recheck SDK-specific deprecations and schema changes in the relevant
reference.
1---2name: clerk-knowledge-patch-23description: Clerk4license: MIT5---678# Clerk Knowledge Patch910Use this guide when implementing, upgrading, or debugging Clerk authentication,11authorization, Organizations, Billing, SDKs, components, or deployment architecture. Start with the migration notes, then open the matching reference.1213## Reference index1415| Reference | Topics |16| --- | --- |17| [Architecture and deployment](references/architecture-and-deployment.md) | Account Portal, FAPI, cookies, handshake, environments, routing, Astro, Next.js, Dashboard roles, Platform API |18| [Authentication and sessions](references/authentication-and-sessions.md) | Factors, SSO, OAuth/OIDC, passkeys, pending sessions, reverification, JWT claims, restrictions |19| [Billing](references/billing.md) | Plans, Features, Subscriptions, trials, checkout, discounts, hooks, administration |20| [Components](references/components.md) | Sign-in-or-up, Waitlist, Google One Tap, Show, loading controls, redirects, Billing drawers |21| [Core 3 migration](references/core-3-migration.md) | Signal API, Expo native UI and hooks, attempt errors, MFA, transfer handling |22| [Customization](references/customization.md) | Appearance, themes, Tailwind, iOS theming, localization, templates, Elements, profile extensions |23| [Frontend resources](references/frontend-resources.md) | Browser API keys, Web3, email links, token cache, user refresh, listeners, multi-session behavior |24| [Go Backend SDK](references/go-backend-sdk.md) | v2 setup, clients, middleware, resources, JWTs, roles, machines, settings |25| [Integrations and webhooks](references/integrations-and-webhooks.md) | Svix webhooks, Inngest, framework middleware, MCP, FAPI proxies, satellites, Chrome extensions |26| [JavaScript Backend SDK](references/javascript-backend-sdk.md) | Request authentication, Next.js token types, user migration, metadata, JWT templates, API keys |27| [Organizations and enterprise](references/organizations-and-enterprise.md) | Tenant scoping, roles, permissions, role sets, invitations, Verified Domains, enterprise connections |28| [Python Backend SDK](references/python-backend-sdk.md) | Authentication, retries, API keys, agent tasks, Billing, machines, releases and breaking schemas |2930## Breaking migrations and changed defaults3132### Migrate custom flows to Core 33334Core 3 uses named factor methods and explicit finalization. Do not port old35`attemptFirstFactor()` or `createdSessionId` activation literally.3637```ts38const { signIn } = useSignIn()39await signIn.create({ identifier: email })40await signIn.password({ password })4142if (signIn.status === 'complete') {43 await signIn.finalize({ navigate: () => router.push('/') })44}45```4647- Email-code sign-in uses `signIn.emailCode.sendCode()` and `verifyCode()`.48- Sign-up verification lives under `signUp.verifications`.49- MFA uses the `signIn.mfa` namespace.50- Read field failures from `errors.fields`, other handled failures from51 `errors.global`, and unparsed failures from `errors.raw`.52- Attempt objects change identity as a flow advances; include the attempt53 object in React dependency arrays.54- Use `clerk.setActive()` for an `existingSession`; use an attempt's55 `finalize()` for a newly completed attempt.5657### Treat pending sessions as unauthenticated by default5859Organization selection, forced-password reset, or required-MFA setup can leave a session `pending`. IDs are normally null and protected routes reject it.60After finalization, inspect `session.currentTask` and route to the task UI. Use `treatPendingAsSignedOut: false` only where pending identity is intentional.6162### Update request-authentication checks6364JavaScript `authenticateRequest()` reports `isAuthenticated`; `isSignedIn` is deprecated. The result distinguishes `signed-in`, `signed-out`, and `handshake`, exposes `tokenType`, and converts through `toAuth()`.6566```ts67const state = await client.authenticateRequest(request, {68 authorizedParties: ['https://app.example.com'],69})70if (!state.isAuthenticated) return new Response('Unauthorized', { status: 401 })71```7273Next.js `auth()` accepts session tokens by default. Explicitly set74`acceptsToken` for API keys, OAuth tokens, or mixed machine routes, then branch75on `tokenType` and scopes.7677### Account for SDK and prop migrations7879- Python 5.x generated schemas can change incompatibly even in patch or minor releases. Pin exact versions and inspect request/response changes; 6.0.0 changes `users.update()` and `organizations.update()` inputs.80- Go v2 requires Go 1.24+ and imports from `github.com/clerk/clerk-sdk-go/v2`.81- `<SignOutButton>` takes `redirectUrl` and `sessionId` directly; `signOutOptions` is deprecated.82- Move `<UserButton>` sign-out destinations to `<ClerkProvider>`; only `afterSwitchSessionUrl` stays local.83- `satelliteAutoSync` defaults to `false`; explicitly enable automatic synchronization.84- Use `CLERK_JS_URL`, not `CLERK_JS`; replace old after-sign-in/up variables with fallback or force redirect settings.85- Replace `sessions.verifySession()` with full-request authentication or direct JWT validation.86- Import extension background clients from `@clerk/chrome-extension/client` with `background: true`.87- Move enterprise administration from `/saml_connections` to `/v1/enterprise_connections`.8889### Rename appearance variables9091Prepare for removal of these deprecated names:9293| Old | Current |94| --- | --- |95| `colorText` | `colorForeground` |96| `colorTextOnPrimaryBackground` | `colorPrimaryForeground` |97| `colorTextSecondary` | `colorMutedForeground` |98| `spacingUnit` | `spacing` |99| `colorInputText` | `colorInputForeground` |100| `colorInputBackground` | `colorInput` |101102## Authentication quick reference103104### Enumeration-safe combined sign-in and sign-up105106Use `signIn.create({ identifier, signUpIfMissing: true })`. Verification107returns `sign_up_if_missing_transfer` for a new account, after which108`signUp.create({ transfer: true })` preserves the verified identifier. This109excludes password, username, restricted, and waitlist flows. The embedded110combined flow can also perform this verification-first behavior under strict111enumeration protection when the instance is open-access and starts without a112password.113114### Reverification115116Server code checks `auth.has({ reverification: preset })` and returns117`reverificationError(preset)`; client code wraps the operation with118`useReverification()`. If the user lacks a second factor, a requested second-119or multi-factor level downgrades to first-factor verification. Native Expo120must provide `onNeedsReverification`; the prebuilt modal is web-only.121122### Session-token claims123124Current session tokens include `v`, `pla`, `fea`, `sts`, and an `o` object only125when an Organization is active. Keep custom claims below 1.2 KB so the complete126cookie stays below browser limits. Use `CLERK_JWT_KEY` or a supplied `jwtKey`127for networkless verification.128129### OAuth and machine tokens130131- Clerk exposes OAuth/OIDC discovery, token, user-info, and token-info132 endpoints.133- Dynamic client registration is public and forces the consent screen on.134- API routes must opt into `oauth_token`; API-key routes must opt into135 `api_key`.136- M2M creation supports locally verifiable JWTs or immediately revocable137 opaque tokens.138- A custom JWT template is independent of a session and cannot include139 session-bound `sid`, `v`, `pla`, or `fea`.140141## Framework and deployment quick reference142143### Next.js144145Calling server-side `auth()` makes the route dynamic. Client `useAuth()` stays146static by default; scope `<ClerkProvider dynamic>` narrowly, optionally under147`<Suspense>`. Built-in FAPI proxying is available through `clerkMiddleware()`148or App Router proxy handlers.149150### Astro151152Endpoints use synchronous `locals.auth()`, `await locals.currentUser()`, and153`clerkClient(context)`. Never serialize the complete Backend User because it154contains `privateMetadata`. Match `isStatic` on Clerk controls to whether the155page is prerendered.156157### Production sessions158159The long-lived `__client` JWT on the FAPI domain is distinct from the one-minute160`__session` JWT on the exact application domain. Cross-subdomain APIs should161receive the session token in `Authorization`. An expired server-rendered token162can trigger a 307 FAPI handshake; preserve Clerk's context headers through163adapters and proxies.164165### Environment topology166167Development instances have a 100-user cap and cannot transfer users to168production. Staging normally needs a separate application and domain. A preview169sharing production identity must use production keys on a subdomain of the170same root domain; provider-owned preview domains use development keys.171172## Organizations and authorization quick reference173174- Store the Organization ID on tenant-owned records and verify it on every175 query.176- Active Organization is tab-local, but the shared cookie can reflect another177 active tab. Fetch a token in the current tab and send it as a bearer token for178 tenant-scoped background work.179- An unknown or unauthorized slug leaves the prior Organization active.180 Compare route `slug` with authenticated `orgSlug` before reading tenant data.181- System Permissions are not session claims. Use equivalent Custom Permissions182 for server-side `has()` checks.183- A Custom Permission succeeds only while the active Organization Plan includes184 its corresponding Feature.185- Role Set changes propagate to assigned Organizations; switching or deleting186 sets requires explicit Role remapping.187- Organization collection hooks fetch nothing unless each collection is188 requested.189190## Billing quick reference191192Clerk Billing objects are separate from Stripe Billing objects. The service is193USD-only and has no native refunds, tax/VAT calculation, 3D Secure confirmation,194or merchant-of-record service. Authorize entitlements with `has()` or `<Show>`,195not display hooks.196197For custom checkout, call `start()`, `confirm()`, then `finalize()` to198synchronize identity state. New cards require `<PaymentElementProvider>` and199`<PaymentElement />`; existing cards pass `paymentMethodId`. Billing buttons200must be inside `<Show when="signed-in">`, and Organization checkout also201requires an Active Organization.202203## UI and customization quick reference204205- `<Show>` accepts roles, permissions, features, plans, or a callback, but only206 hides client content; repeat sensitive checks on the server.207- `<GoogleOneTap>` needs custom Google credentials and does not return provider208 access tokens.209- Embedded `<Waitlist />` needs Waitlist mode plus `waitlistUrl`.210- Global appearance supports `theme`, `options`, `variables`, `elements`,211 `captcha`, and `cssLayerName`; direct component appearance wins for one212 instance.213- For Tailwind v4, place Clerk in an earlier cascade layer than `utilities`.214- Stable DOM hooks are the human-readable `cl-*` classes before the lock marker;215 remove `cl-` when using an `appearance.elements` key.216- Hosted Account Portal pages allow Dashboard customization only; prebuilt217 components allow CSS changes; Elements allows custom HTML/CSS but still owns218 flow order; only API-built flows control authentication logic.219220## Native Expo quick reference221222`@clerk/expo` 3.1 requires Expo SDK 53+. Its config plugin installs native iOS223and Android dependencies. `AuthView`, `UserButton`, and `UserProfileView` come224from `@clerk/expo/native`; native Google sign-in uses platform-native APIs. Set225the plugin's `appleSignIn` option to `false` when the entitlement is not needed.226227Use `useUserProfileModal()`, `useNativeSession()`, and `useNativeAuthEvents()`228for native state. Trusted-device APIs can enroll a device for later biometric229sign-in. Cloudflare bot protection is unsupported in Expo and must be disabled230there.231232## Before shipping2332341. Confirm accepted token types and authorized parties for every backend route.2352. Enforce tenant and entitlement checks on the server, even when UI controls236 hide content.2373. Handle handshake, pending-session, and reverification states explicitly.2384. Check redirect URLs, Account Portal return targets, proxy headers, and239 satellite origins.2405. Capture API-key secrets and OAuth client secrets at creation; they are not241 generally retrievable later.2426. Recheck SDK-specific deprecations and schema changes in the relevant243 reference.