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 topic 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, trusted devices, pending sessions, reverification, JWT claims, restrictions |
| Billing |
Plans, Features, Subscriptions, trials, discounts, checkout, 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 and sync |
| 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 in code that intentionally handles pending
identity.
Update request-authentication checks
JavaScript authenticateRequest() reports isAuthenticated; isSignedIn is
deprecated. The result can be signed-in, signed-out, or 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 and 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 remains local to the button.
satelliteAutoSync defaults to false. Set it explicitly when automatic synchronization is required.
- Use
CLERK_JS_URL, not deprecated CLERK_JS; replace old after-sign-in/up environment variables with fallback or force redirect settings.
- Replace
sessions.verifySession() with full-request authentication or direct JWT validation.
- Import Chrome 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
Combined sign-in-or-up without enumeration
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
<SignIn /> equivalent supports strict enumeration protection for open-access
email or phone flows that do not start with password; Account Portal does not
support the combined flow.
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 can expose OAuth/OIDC discovery, token, user-info, and token-info
endpoints.
- Dynamic client registration is public and forces the consent screen on.
- Public OAuth clients can identify themselves with a beta HTTPS Client ID
Metadata Document when the workspace enables that support.
- 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() remains
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.
- Self-service OIDC requires Organization enablement, a managing administrator, DNS domain verification, and a successful connection test before activation.
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. Discounts can be fixed or percentage-based and checkout
promo codes can constrain redemption and new-subscriber eligibility.
UI and customization quick reference
<Show> accepts roles, permissions, features, plans, or a callback, but it 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 appleSignIn: false when the entitlement is not needed.
Use useUserProfileModal(), useNativeSession(), and useNativeAuthEvents()
for native state. useTrustedDevices() handles biometric device enrollment.
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-patch3description: 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 topic 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, trusted devices, pending sessions, reverification, JWT claims, restrictions |19| [Billing](references/billing.md) | Plans, Features, Subscriptions, trials, discounts, checkout, 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 and sync |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 from `errors.global`, and unparsed failures from `errors.raw`.51- Attempt objects change identity as a flow advances; include the attempt object in React dependency arrays.52- Use `clerk.setActive()` for an `existingSession`; use an attempt's `finalize()` for a newly completed attempt.5354### Treat pending sessions as unauthenticated by default5556Organization selection, forced-password reset, or required-MFA setup can leave57a session `pending`. IDs are normally null and protected routes reject it.58After finalization, inspect `session.currentTask` and route to the task UI. Use59`treatPendingAsSignedOut: false` only in code that intentionally handles pending60identity.6162### Update request-authentication checks6364JavaScript `authenticateRequest()` reports `isAuthenticated`; `isSignedIn` is65deprecated. The result can be `signed-in`, `signed-out`, or `handshake`, exposes66`tokenType`, and converts through `toAuth()`.6768```ts69const state = await client.authenticateRequest(request, {70 authorizedParties: ['https://app.example.com'],71})72if (!state.isAuthenticated) {73 return new Response('Unauthorized', { status: 401 })74}75```7677Next.js `auth()` accepts session tokens by default. Explicitly set78`acceptsToken` for API keys, OAuth tokens, or mixed machine routes, then branch79on `tokenType` and scopes.8081### Account for SDK and prop migrations8283- Python 5.x generated schemas can change incompatibly even in patch or minor releases. Pin exact versions and inspect request and response changes; 6.0.0 changes `users.update()` and `organizations.update()` inputs.84- Go v2 requires Go 1.24+ and imports from `github.com/clerk/clerk-sdk-go/v2`.85- `<SignOutButton>` takes `redirectUrl` and `sessionId` directly; `signOutOptions` is deprecated.86- Move `<UserButton>` sign-out destinations to `<ClerkProvider>`; only `afterSwitchSessionUrl` remains local to the button.87- `satelliteAutoSync` defaults to `false`. Set it explicitly when automatic synchronization is required.88- Use `CLERK_JS_URL`, not deprecated `CLERK_JS`; replace old after-sign-in/up environment variables with fallback or force redirect settings.89- Replace `sessions.verifySession()` with full-request authentication or direct JWT validation.90- Import Chrome extension background clients from `@clerk/chrome-extension/client` with `background: true`.91- Move enterprise administration from `/saml_connections` to `/v1/enterprise_connections`.9293### Rename appearance variables9495Prepare for removal of these deprecated names:9697| Old | Current |98| --- | --- |99| `colorText` | `colorForeground` |100| `colorTextOnPrimaryBackground` | `colorPrimaryForeground` |101| `colorTextSecondary` | `colorMutedForeground` |102| `spacingUnit` | `spacing` |103| `colorInputText` | `colorInputForeground` |104| `colorInputBackground` | `colorInput` |105106## Authentication quick reference107108### Combined sign-in-or-up without enumeration109110Use `signIn.create({ identifier, signUpIfMissing: true })`. Verification returns111`sign_up_if_missing_transfer` for a new account, after which112`signUp.create({ transfer: true })` preserves the verified identifier. This113excludes password, username, restricted, and waitlist flows. The embedded114`<SignIn />` equivalent supports strict enumeration protection for open-access115email or phone flows that do not start with password; Account Portal does not116support the combined flow.117118### Reverification119120Server code checks `auth.has({ reverification: preset })` and returns121`reverificationError(preset)`; client code wraps the operation with122`useReverification()`. If the user lacks a second factor, a requested second-123or multi-factor level downgrades to first-factor verification. Native Expo must124provide `onNeedsReverification`; the prebuilt modal is web-only.125126### Session-token claims127128Current session tokens include `v`, `pla`, `fea`, `sts`, and an `o` object only129when an Organization is active. Keep custom claims below 1.2 KB so the complete130cookie stays below browser limits. Use `CLERK_JWT_KEY` or a supplied `jwtKey`131for networkless verification.132133### OAuth and machine tokens134135- Clerk can expose OAuth/OIDC discovery, token, user-info, and token-info136 endpoints.137- Dynamic client registration is public and forces the consent screen on.138- Public OAuth clients can identify themselves with a beta HTTPS Client ID139 Metadata Document when the workspace enables that support.140- API routes must opt into `oauth_token`; API-key routes must opt into141 `api_key`.142- M2M creation supports locally verifiable JWTs or immediately revocable143 opaque tokens.144- A custom JWT template is independent of a session and cannot include145 session-bound `sid`, `v`, `pla`, or `fea`.146147## Framework and deployment quick reference148149### Next.js150151Calling server-side `auth()` makes the route dynamic. Client `useAuth()` remains152static by default; scope `<ClerkProvider dynamic>` narrowly, optionally under153`<Suspense>`. Built-in FAPI proxying is available through `clerkMiddleware()`154or App Router proxy handlers.155156### Astro157158Endpoints use synchronous `locals.auth()`, `await locals.currentUser()`, and159`clerkClient(context)`. Never serialize the complete Backend User because it160contains `privateMetadata`. Match `isStatic` on Clerk controls to whether the161page is prerendered.162163### Production sessions164165The long-lived `__client` JWT on the FAPI domain is distinct from the one-minute166`__session` JWT on the exact application domain. Cross-subdomain APIs should167receive the session token in `Authorization`. An expired server-rendered token168can trigger a 307 FAPI handshake; preserve Clerk's context headers through169adapters and proxies.170171### Environment topology172173Development instances have a 100-user cap and cannot transfer users to174production. Staging normally needs a separate application and domain. A preview175sharing production identity must use production keys on a subdomain of the same176root domain; provider-owned preview domains use development keys.177178## Organizations and authorization quick reference179180- Store the Organization ID on tenant-owned records and verify it on every query.181- 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.182- An unknown or unauthorized slug leaves the prior Organization active. Compare route `slug` with authenticated `orgSlug` before reading tenant data.183- System Permissions are not session claims. Use equivalent Custom Permissions for server-side `has()` checks.184- A Custom Permission succeeds only while the active Organization Plan includes its corresponding Feature.185- Role Set changes propagate to assigned Organizations; switching or deleting sets requires explicit Role remapping.186- Organization collection hooks fetch nothing unless each collection is requested.187- Self-service OIDC requires Organization enablement, a managing administrator, DNS domain verification, and a successful connection test before activation.188189## Billing quick reference190191Clerk Billing objects are separate from Stripe Billing objects. The service is192USD-only and has no native refunds, tax/VAT calculation, 3D Secure confirmation,193or merchant-of-record service. Authorize entitlements with `has()` or `<Show>`,194not display hooks.195196For custom checkout, call `start()`, `confirm()`, then `finalize()` to synchronize197identity state. New cards require `<PaymentElementProvider>` and198`<PaymentElement />`; existing cards pass `paymentMethodId`. Billing buttons199must be inside `<Show when="signed-in">`, and Organization checkout also requires200an Active Organization. Discounts can be fixed or percentage-based and checkout201promo codes can constrain redemption and new-subscriber eligibility.202203## UI and customization quick reference204205- `<Show>` accepts roles, permissions, features, plans, or a callback, but it only hides client content; repeat sensitive checks on the server.206- `<GoogleOneTap>` needs custom Google credentials and does not return provider access tokens.207- Embedded `<Waitlist />` needs Waitlist mode plus `waitlistUrl`.208- Global appearance supports `theme`, `options`, `variables`, `elements`, `captcha`, and `cssLayerName`; direct component appearance wins for one instance.209- For Tailwind v4, place Clerk in an earlier cascade layer than `utilities`.210- Stable DOM hooks are the human-readable `cl-*` classes before the lock marker; remove `cl-` when using an `appearance.elements` key.211- 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.212213## Native Expo quick reference214215`@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 `appleSignIn: false` when the entitlement is not needed.216217Use `useUserProfileModal()`, `useNativeSession()`, and `useNativeAuthEvents()`218for native state. `useTrustedDevices()` handles biometric device enrollment.219Cloudflare bot protection is unsupported in Expo and must be disabled there.220221## Before shipping2222231. Confirm accepted token types and authorized parties for every backend route.2242. Enforce tenant and entitlement checks on the server even when UI controls hide content.2253. Handle handshake, pending-session, and reverification states explicitly.2264. Check redirect URLs, Account Portal return targets, proxy headers, and satellite origins.2275. Capture API-key secrets and OAuth client secrets at creation; they are not generally retrievable later.2286. Recheck SDK-specific deprecations and schema changes in the relevant reference.