Support min_remaining_ttl_seconds for M2M token creation. (#8513) by @wobsoriano
Usage:
clerkClient.m2m.createToken({
machineSecretKey: 'ak_xxxxx',
minRemainingTtlSeconds: 240,
});
Add RoleSetJSON, RoleSetItemJSON, and RoleSetMigrationJSON types matching the BAPI OpenAPI schema. Add role_set_key, last_active_at, and missing_member_with_elevated_permissions to OrganizationJSON. (#8502) by @jacekradko
Updated dependencies [5cda3ee]:
Fix OAuth consent component and hook related types. (#8483) by @SarahSoutoul
Updated dependencies [7a5892f]:
1bfd8ab]:
Auto-proxy FAPI requests for .vercel.app subdomains. When deployed to a .vercel.app domain without explicit proxy or domain configuration, the SDK automatically routes Frontend API requests through /__clerk on the app's own origin. This enables Clerk production mode on Vercel deployments without manual proxy setup. (#8035) by @brkalow
Fix Request cloning and outbound fetch to omit cross-realm AbortSignal. Node 24's bundled undici tightened the instanceof AbortSignal check on RequestInit.signal, which broke: (#8351) by @jacekradko
NextRequest in @clerk/backend's ClerkRequest.Requests passed through patchRequest in @clerk/react-router and @clerk/tanstack-react-start.@clerk/backend's clerkFrontendApiProxy, which forwarded the inbound request's signal to the upstream fetch. Abort propagation will be restored in a follow-up via an in-realm AbortController bridge.Updated dependencies [9b57986, a9f9b29]:
da76490]:
createBootstrapSignedOutState helper to @clerk/backend/internal. Returns a synthetic UnauthenticatedState<'session_token'> without requiring a publishable key or an AuthenticateContext. Intended for framework integrations that need to run authorization logic before real Clerk keys are available (e.g. the Next.js keyless bootstrap window). Accepts optional signInUrl, signUpUrl, isSatellite, domain, and proxyUrl so that createRedirect-driven flows (including cross-origin satellite sign-in with the __clerk_status=needs-sync handshake marker) behave correctly during bootstrap. (#8368) by @jacekradkoA clock skew of 0 will not fall back to the default value anymore. (#8359) by @dominic-clerk
Updated dependencies [d52b311]:
joinPaths (#8331) by @dominic-clerkIntroduce samlConnection and oauthConfig into the EnterpriseConnection resource. (#8326) by @LauraBeatris
The JWT claims are verified after the signature to avoid leaking information through error messages on forged tokens. (#8332) by @dominic-clerk
Updated dependencies [c7b0f47, 34762e8]:
b0b6675]:
dc2de16]:
sec-fetch-dest: document incorrectly triggering handshake redirects, resulting in 405 errors from FAPI. Non-GET requests (e.g. native form submissions) are now excluded from handshake and multi-domain sync eligibility. (#8045) by @jacekradkoExport OrganizationInvitationAcceptedWebhookEvent type. (#8235) by @wobsoriano
Updated dependencies [2c06a5f]:
Export ClerkAPIResponseError and ClerkRuntimeError classes from error subpaths for consistency with the already-exported type guards. (#8228) by @jacekradko
feat: add orderBy argument to getInvitationList to control sorting (supports leading '+' for ascending and '-' for descending) (#7137) by @mario-jerkovic
Updated dependencies [b289566, 636b496, aa63796]:
Fix frontend API proxy following redirects server-side instead of passing them to the browser. The proxy's fetch() call now uses redirect: 'manual' so that 3xx responses from FAPI (e.g. after OAuth callbacks) are returned to the client as-is, matching standard HTTP proxy behavior. (#8186) by @brkalow
Improve the built-in Clerk Frontend API proxy, adding support for abort signals and addressing a number of small edge cases. (#8163) by @brkalow
Add EnterpriseAccount and EnterpriseAccountConnection classes to @clerk/backend, restoring enterprise SSO account data on the User object that was lost when samlAccounts was removed in v3. (#8181) by @iagodahlem
Updated dependencies [9a00a1c, 00715a6, b8c73d3, 1827b50, 7707a31]:
Fix ERR_CONTENT_DECODING_FAILED when loading proxied assets by requesting uncompressed responses from FAPI and stripping Content-Encoding/Content-Length headers that fetch() invalidates through auto-decompression. (#8159) by @brkalow
Fix satelliteAutoSync to default to false as documented. Previously, not passing the prop resulted in undefined, which was treated as true due to a strict equality check (=== false). This preserved Core 2 auto-sync behavior instead of the intended Core 3 default. The check is now !== true, so both undefined and false skip automatic satellite sync. (#8001) by @nikosdouvlis
Fix an issue where multiple set-cookie headers were being dropped by the frontend API proxy. (#8162) by @brkalow
b9cb6e5]:
EnterpriseConnection resource, allowing to create both OIDC and SAML connections (#8017) by @LauraBeatrisFix casing of enterprise connection API params when sending saml or oidc configuration (#8022) by @LauraBeatris
Updated dependencies [de1386f]:
3e63793]:
Fix clerkFrontendApiProxy to derive the Clerk-Proxy-Url header and Location rewrites from x-forwarded-proto/x-forwarded-host headers instead of the raw request.url. Behind a reverse proxy, request.url resolves to localhost, causing FAPI to receive an incorrect proxy URL. The fix uses the same forwarded-header resolution pattern as ClerkRequest. (#7994) by @nikosdouvlis
Remove experimental comment from Agent Tasks API (#7978) by @tmilewski
Updated dependencies [776ee1b, 7fb870d, 09cb6d4]:
package.json engine and peer dependency constraints. (#7972) by @jacekradkoRemove deprecated verify methods in favor of verify(). (#7927) by @wobsoriano
apiKeys.verifySecret() removed
// Before
await clerkClient.apiKeys.verifySecret(secret);
// After
await clerkClient.apiKeys.verify(secret);
idpOAuthAccessToken.verifyAccessToken() removed
// Before
await clerkClient.idpOAuthAccessToken.verifyAccessToken(accessToken);
// After
await clerkClient.idpOAuthAccessToken.verify(accessToken);
m2m.verifyToken() removed
// Before
await clerkClient.m2m.verifyToken(params);
// After
await clerkClient.m2m.verify(params);
Update engines config to require node@20 or higher (#6931) by @jacekradko
Remove deprecated samlAccount in favor of enterpriseAccount (#7258) by @LauraBeatris
Add support for Agent Tasks API endpoint which allows developers to create agent tasks that can be used to act on behalf of users through automated flows. (#7783) by @tmilewski
Add Frontend API proxy support via frontendApiProxy option in clerkMiddleware (#7602) by @brkalow
Add satelliteAutoSync option to optimize satellite app handshake behavior (#7597) by @nikosdouvlis
Satellite apps currently trigger a handshake redirect on every first page load, even when no cookies exist. This creates unnecessary redirects to the primary domain for apps where most users aren't authenticated.
New option: satelliteAutoSync (default: false)
false (default): Skip automatic handshake if no session cookies exist, only trigger after explicit sign-in actiontrue: Satellite apps automatically trigger handshake on first load (previous behavior)New query parameter: __clerk_sync
__clerk_sync=1 (NeedsSync): Triggers handshake after returning from primary sign-in__clerk_sync=2 (Completed): Prevents re-sync loop after handshake completesBackwards compatible: Still reads legacy __clerk_synced=true parameter.
SSR redirect fix: Server-side redirects (e.g., redirectToSignIn() from middleware) now correctly add __clerk_sync=1 to the return URL for satellite apps. This ensures the handshake is triggered when the user returns from sign-in on the primary domain.
CSR redirect fix: Client-side redirects now add __clerk_sync=1 to all redirect URL variants (forceRedirectUrl, fallbackRedirectUrl) for satellite apps, not just the default redirectUrl.
import { clerkMiddleware } from '@clerk/nextjs/server';
export default clerkMiddleware({
isSatellite: true,
domain: 'satellite.example.com',
signInUrl: 'https://primary.example.com/sign-in',
// Set to true to automatically sync auth state on first load
satelliteAutoSync: true,
});
import { clerkMiddleware } from '@clerk/tanstack-react-start/server';
export default clerkMiddleware({
isSatellite: true,
domain: 'satellite.example.com',
signInUrl: 'https://primary.example.com/sign-in',
// Set to true to automatically sync auth state on first load
satelliteAutoSync: true,
});
<ClerkProvider
publishableKey='pk_...'
isSatellite={true}
domain='satellite.example.com'
signInUrl='https://primary.example.com/sign-in'
// Set to true to automatically sync auth state on first load
satelliteAutoSync={true}
>
{children}
</ClerkProvider>
import { clerkMiddleware } from '@clerk/tanstack-react-start/server';
// Options callback - receives context object, returns options
export default clerkMiddleware(({ url }) => ({
isSatellite: true,
domain: 'satellite.example.com',
signInUrl: 'https://primary.example.com/sign-in',
satelliteAutoSync: url.pathname.startsWith('/dashboard'),
}));
satelliteAutoSync defaults to falsePreviously, satellite apps would automatically trigger a handshake redirect on every first page load to sync authentication state with the primary domain—even when no session cookies existed. This caused unnecessary redirects to the primary domain for users who weren't authenticated.
The new default (satelliteAutoSync: false) provides a better experience for end users. Performance-wise, the satellite app can be shown immediately without attempting to sync state first, which is the right behavior for most use cases.
To preserve the previous behavior where visiting a satellite while already signed in on the primary domain automatically syncs your session, set satelliteAutoSync: true:
export default clerkMiddleware({
isSatellite: true,
domain: 'satellite.example.com',
signInUrl: 'https://primary.example.com/sign-in',
satelliteAutoSync: true, // Opt-in to automatic sync on first load
});
The clerkMiddleware function no longer accepts individual props as functions. If you were using the function form for props like domain, proxyUrl, or isSatellite, migrate to the options callback pattern.
Before (prop function form - no longer supported):
import { clerkMiddleware } from '@clerk/tanstack-react-start/server';
export default clerkMiddleware({
isSatellite: true,
// ❌ Function form for individual props no longer works
domain: url => url.hostname,
});
After (options callback form):
import { clerkMiddleware } from '@clerk/tanstack-react-start/server';
// ✅ Wrap entire options in a callback function
export default clerkMiddleware(({ url }) => ({
isSatellite: true,
domain: url.hostname,
}));
The callback receives a context object with the url property (a URL instance) and can return options synchronously or as a Promise for async configuration.
Warn when a cookie-based session token is missing the azp claim instead of rejecting the token. This prepares consumers for a future version where the azp claim will be required. (#7929) by @jacekradko
Dropping the __experimental_ prefix from setPasswordCompromised and unsetPasswordCompromised and marking them as stable (#7504) by @octoper
Added date filter parameters to user list endpoint (#7793) by @wobsoriano
Fixes an issue with host header parsing that would cause Clerk to throw an exception when receiving malformed host values. (#7370) by @brkalow
Improve token type validation in authentication requests (#7765) by @wobsoriano
Allow null for period_end in BillingSubscriptionItemWebhookEventJSON (#7699) by @jacekradko
fix: Update getAuthData to use isMachineToken (#7755) by @jeremy-clerk
Allow usage of machine secret key when listing M2M tokens: (#7968) by @wobsoriano
const clerkClient = createClerkClient();
const m2mToken = await clerkClient.m2m.list({
machineSecretKey: 'ak_xxxxx',
subject: machineId,
});
Add missing fields to CommercePlan type. (#7707) by @dstaley
Updated dependencies [0a9cce3, e35960f, c9f0d77, 1bd1747, 6a2ff9e, d2cee35, 0a9cce3, a374c18, 466d642, 5ef4a77, af85739, 10b5bea, a05d130, b193f79, e9d2f2f, 43fc7b7, 0f1011a, cbc5618, 38def4f, 7772f45, a3e689f, 583f7a9, 965e7f1, 2b76081, f284c3d, ac34168, cf0d0dc, 690280e, b971d0b, 22d1689, e9a1d4d, c088dde, 8902e21, 972f6a0, a1aaff3, d85646a, ab3dd16, 4a8cb10, fd195c1, 8887fac, dc886a9, 428629b, 8b95393, c438fa5, c438fa5, fd195c1, fd69edb, 8d91225, 1fc95e2, 3dac245, a4c3b47, 7c3c002, d8bbc66, 3983cf8, f1f1d09, 736314f, 2cc7dbb, 86d2199, da415c8, 97c9ab3, cc63aab, a7a38ab, cfa70ce, 25d37b0, 26254f0, c97e6af, d98727e, 79e2622, 12b3070]:
Added support for JWT token format when creating and verifying machine-to-machine (M2M) tokens. This enables fully networkless verification when using the public JWT key. (#7883) by @wobsoriano
Creating a JWT-format M2M token
const clerkClient = createClerkClient({
machineSecretKey: process.env.CLERK_MACHINE_SECRET_KEY,
});
const m2mToken = await clerkClient.m2m.createToken({
tokenFormat: 'jwt',
});
console.log('M2M token created:', m2mToken.token);
Verifying a token
const clerkClient = createClerkClient({
machineSecretKey: process.env.CLERK_MACHINE_SECRET_KEY,
});
const authHeader = req.headers.get('Authorization');
const token = authHeader.slice(7);
const verified = await clerkClient.m2m.verify(token);
console.log('Verified M2M token:', verified);
Networkless verification
const clerkClient = createClerkClient({
jwtKey: process.env.CLERK_JWT_KEY,
});
const authHeader = req.headers.get('Authorization');
const token = authHeader.slice(7);
const verified = await clerkClient.m2m.verify(token);
console.log('Verified M2M token:', verified);
Add list() method to M2M tokens API to retrieve a list of machine-to-machine tokens for a given machine. (#7939) by @wobsoriano
// Retrieve M2M tokens for a specific machine
const response = await clerkClient.m2m.list({
subject: 'mch_1xxxxxxxxxxxxx',
});
console.log(response.data); // M2MToken[]
console.log(response.totalCount); // number
Filter by revoked or expired tokens:
const revokedTokens = await clerkClient.m2m.list({
subject: 'mch_1xxxxxxxxxxxxx',
revoked: true,
});
const expiredTokens = await clerkClient.m2m.list({
subject: 'mch_1xxxxxxxxxxxxx',
expired: true,
});
7955e9d]:
8a0c404]:
OrganizationInvitationStatus to include expired to match the API updates. (#7909) by @austincalvelageAdd support for Agent Tasks API endpoint which allows developers to create agent tasks that can be used to act on behalf of users through automated flows. (#7897) by @tmilewski
Export createAgentTestingTask helper for creating agent tasks via the Clerk Backend API from both @clerk/testing/playwright and @clerk/testing/cypress subpaths.
c00c524]:
fix(backend): type JwtTemplatesApi.list as PaginatedResourceResponse (#7868) by @thiskevinwang
Updated dependencies [71bd53c, 935f780]:
b17e4bb]:
Add providerUserId field to ExternalAccount resource as the preferred way to access the unique user ID from the OAuth provider. The existing externalId field is now deprecated in favor of providerUserId for better clarity and consistency across the API. (#7778) by @Jibaru
Add createBulk() method to WaitlistEntryAPI for bulk creating waitlist entries (#7762) by @Jibaru
35bcbd1]:
Add lastSignInAtAfter and lastSignInAtBefore filters to the Users API list and count endpoints. (#7721) by @Jibaru
These parameters are supported by users.getUserList() and are forwarded to /v1/users and /v1/users/count to filter users by last sign-in timestamp.
createInvitationBulk return type to Promise<Invitation[]> (#7702) by @jacekradko64a35f7]:
b7a4e1e]:
e995cc3]:
Add optional idToken member to OauthAccessToken returned by getUserOauthAccessToken. The ID token is retrieved from OIDC providers and is only present for OIDC-compliant OAuth 2.0 providers when available. (#7599) by @jfoshee
Updated dependencies [271ddeb]:
acceptsToken values in authenticateRequest. When acceptsToken is an array containing both session and machine token types (e.g., ['session_token', 'api_key']), the function now correctly routes to the appropriate authentication handler based on the actual token type, instead of always treating them as machine tokens. (#7556) by @wobsorianoMove cookie to devDependencies and bundle it within @clerk/backend to fix module compatibility problems in TanStack Start apps. (#7545) by @nikosdouvlis
Updated dependencies [a4e6932]:
03dd374]:
__experimental_ prefix from setPasswordCompromised and unsetPasswordCompromised and marking them as stable (#7503) by @octoperRenaming __experimental_passwordCompromised to __experimental_setPasswordCompromised and introducing __experimental_unsetPasswordCompromised (#7477) by @octoper
Updated dependencies [79eb5af, b3b02b4, 7b3024a, 2cd4da9]:
Fixed an issue where TanStack React Start middleware fails to properly handle requests. (#7431) by @wobsoriano
Updated dependencies [375a32d, 175883b, f626046, 14342d2]:
Added API keys get, delete and update methods. (#7400) by @wobsoriano
Usage:
await clerkClient.apiKeys.get('api_key_id');
await clerkClient.apiKeys.update({
apiKeyId: 'api_key_id',
scopes: ['scope1', 'scope2'],
});
await clerkClient.apiKeys.delete('api_key_id');