JavaScript SDK
npx @buildinternet/releases get clerk-javascript-sdknpx @buildinternet/releases get clerk-javascript-sdk25d8633]:
Authorization header when acceptsToken is 'any' or an array that includes 'session_token'. authenticateRequest() now returns a signed-out state with reason token-type-mismatch for such a token, matching the existing acceptsToken: 'session_token' behavior. (#9511) by @dominic-clerkAlign JSDoc link targets with the docs link rules: internal docs links don't open in a new tab (removed {{ target: '_blank' }} from the Invitation Metadata link), while API reference links do (added it to the ExternalAccount Backend API link and the currentUser() endpoint link). (#9556) by @manovotny
Updated dependencies [0d224f2]:
dbaa95a]:
Mark the internal createBootstrapSignedOutState as deprecated. It is no longer used by @clerk/nextjs and is kept only for older published SDK versions. (#9493) by @djgould
Updated dependencies [ea8cb05]:
authenticateRequest() now returns a signed-out state with reason token-type-mismatch for such a token in the Authorization header or __session cookie. Tokens with no category tag, and instances configured to omit it, are unaffected. (#9469) by @dominic-clerkScope the JWKS cache per Clerk instance. The cache was keyed on the JWT kid alone and shared across the whole process, so an application verifying tokens for more than one Clerk instance (for example the Dynamic Keys / multi-tenant pattern) could resolve a signing key that was fetched for a different instance. Keys are now cached separately per secret key and API URL, so a token can only be verified against the instance whose credentials fetched its signing key. (#9394) by @dominic-clerk
Networkless verification with jwtKey had the same flaw: the JWK derived from the PEM was cached by kid alone, so a process verifying tokens with different jwtKey values could resolve a key derived from another instance's PEM. The JWK is now always derived from the jwtKey that was passed in.
The jwk-kid-mismatch error message no longer lists the key IDs currently held in the cache.
Fix Cookie header parsing in authenticateRequest() to follow RFC 6265 and guard against a non-string iss. Legitimate cookies and JWTs are unaffected. (#9466) by @dominic-clerk
Updated dependencies [b815047]:
7f5c294]:
Billing applied-discount snapshots now include optional durationInCycles. Payment attempt and statement UIs use the original discount length instead of cycles remaining, and omit the duration copy when it is unavailable. (#9401) by @mauricioabreu
Updated dependencies [81840b3, b7fb564, 44edcc9]:
lockUser() documentation to link to the current Rules page in the Clerk Dashboard. (#9372) by @SarahSoutoul131edec]:
Use a root-relative link (/contact/support) for the passwordHasher "contact support" reference so the generated API reference renders it as an internal same-tab link instead of an external one. (#9347) by @manovotny
Updated dependencies [34d278b]:
clerkClient.users.removePassword(userId, params?) to remove a user's password through the Backend API. Password removal is allowed even when the user has no alternate sign-in method configured. Existing sessions remain active by default; pass { signOutOfOtherSessions: true } to revoke them. (#9326) by @joshrowleyImprove generated API reference links, expose BillingSubscriptionItemStatus, and clarify the createUser() identification status documentation. (#9340) by @SarahSoutoul
Updated dependencies [1ef84c3, d639048, a66cbbf]:
Add the optional emailAddressIdentificationStatus and phoneNumberIdentificationStatus parameters to CreateUserParams. The Backend API has supported these arrays on POST /v1/users since they shipped, but createUser() had no way to pass them, so every email address and phone number was necessarily created verified. Each array runs parallel to emailAddress / phoneNumber — one item per identifier, applied by position — and an item set to 'reserved' creates that identifier unverified but still usable for sign-in and locked so no other user can claim it. (#9305) by @dmoerner
The createUser() documentation is corrected accordingly: it stated unconditionally that created email addresses and phone numbers are automatically verified, which is only the default.
Updated dependencies [5c81479]:
Return a TokenVerificationError from decodeJwt and verifyToken for tokens whose header, payload, or signature cannot be decoded. (#9268) by @wobsoriano
Updated dependencies [aaea141]:
EnterpriseConnection response resource with what the Backend API actually returns: (#9156) by @manovotny
EnterpriseConnection now exposes provider, logoPublicUrl, allowOrganizationAccountLinking, authenticatable, disableJitProvisioning, and customAttributes.EnterpriseConnectionSamlConnection now exposes active, forceAuthn, and loginHint.EnterpriseConnectionOauthConfig now exposes providerKey, authUrl, tokenUrl, userInfoUrl, and requiresPkce.undefined despite their declared types: allowSubdomains on EnterpriseConnection (use samlConnection.allowSubdomains), and idpMetadata and syncUserAttributes on EnterpriseConnectionSamlConnection (use the top-level syncUserAttributes).organizationId is now normalized to null when the Backend API omits it, matching its declared string | null type. Properties backed by optional API fields (for example oauthConfig.clientId and the SAML IdP fields) are now typed as possibly undefined to match runtime behavior.blockDisposableEmailDomains bolded "Block sign-ups that use disposable email domains", but the toggle in the Clerk Dashboard is "Block sign-ups that use disposable email addresses". ignoreDotsForGmailAddresses bolded "Ignore dots for Gmail addresses" as a Dashboard toggle, but no such control exists — the wording now matches the equivalent comment on UpdateRestrictionsParams. Property names are unchanged. (#9253) by @manovotny01f2c12]:
fapiUrl option to Frontend API proxy helpers so requests can target a custom Clerk Frontend API URL. (#9223) by @thiskevinwang097432d]:
Fix a cross-origin handshake bypass where isKnownClerkReferrer() trusted overly broad referrer hosts as Clerk-owned: any accounts.* host (e.g. accounts.attacker.com), plus dev account-portal domains (*.accounts.dev and legacy suffixes) on production instances. These let unrelated origins skip the handshake and its session-freshness check. The referrer is now trusted only for the accounts portal derived from the instance's frontend API, plus dev account-portal domains on non-production instances. (#9145) by @dominic-clerk
Add an optional orgId parameter to createSignInToken() for activating an Organization when the token is redeemed. (#9192) by @swolfand
Standardize JSDoc punctuation to always follow e.g. and i.e. with a comma (e.g., / i.e.,), matching the docs style guide. Comment-only change; no runtime behavior is affected. This keeps the generated Typedoc reference output consistent. (#9201) by @SarahSoutoul
Add the required provider field to CreateEnterpriseConnectionParams. The Backend API has always required provider when creating an enterprise connection, so calls to createEnterpriseConnection() without it type-checked but failed at runtime. The field is typed to the supported provider values ('saml_custom', 'saml_okta', 'saml_google', 'saml_microsoft', 'oidc_custom', 'oidc_github_enterprise', 'oidc_gitlab'), so unsupported values are also caught at compile time. (#9155) by @manovotny
Add the remaining optional enterprise connection parameters supported by the Backend API. CreateEnterpriseConnectionParams and UpdateEnterpriseConnectionParams now accept allowOrganizationAccountLinking, customAttributes, authenticatable, and disableJitProvisioning (update also accepts disableAdditionalIdentifications), and SAML params accept loginHint for configuring the login_hint sent to the IdP. (#9155) by @manovotny
Align CreateEnterpriseConnectionParams and UpdateEnterpriseConnectionParams with the Backend API contract: (#9155) by @manovotny
name and domains are now required on CreateEnterpriseConnectionParams. The Backend API already rejected requests missing either of them, so calls that omitted these fields failed at runtime; the types now surface this at compile time.syncUserAttributes on CreateEnterpriseConnectionParams. The Backend API ignores this parameter on create; use updateEnterpriseConnection() to set it.provider on UpdateEnterpriseConnectionParams. The Backend API ignores this parameter on update; the provider cannot be changed after creation.Updated dependencies [858a689, c904fb4]:
Reject machine tokens (M2M and OAuth JWTs) presented in the __session cookie. Previously such a token could pass session verification and produce a signed-in state with the machine identity as userId, defeating if (userId) authorization checks. The cookie path now mirrors the existing header-path guard and returns a signed-out state for these tokens. (#9168) by @dominic-clerk
Updated dependencies [bcbdda6]:
Add CLERK_DISABLE_AUTO_PROXY=true to opt out of automatic Frontend API proxying on Vercel production deployments. (#9159) by @brkalow
Updated dependencies [e162b71]:
M2MToken, APIKey, and IdPOAuthAccessToken JSDoc that the timestamp properties (expiration, lastUsedAt, createdAt, and updatedAt) are Unix timestamps in milliseconds (not seconds). (#9122) by @SarahSoutoul8dbf343]:
Improve satellite-domain redirect loop diagnostics. (#8636) by @jescalan
Updated dependencies [62f6702]:
Enforce the azp (authorized party) claim when authorizedParties is configured. Previously, a session token that was missing the azp claim was accepted even when authorizedParties was set, allowing the authorized-parties check to be bypassed by omitting the claim. Now, when authorizedParties is configured, a token with a missing or empty azp claim is rejected. Tokens without azp continue to be accepted when no authorizedParties are configured. (#8877) by @dominic-clerk
Updated dependencies [6f97ef5, bab1f29, f2d9e4b]:
idpCertificateIssuedAt and idpCertificateExpiresAt to SAML enterprise connections, exposing the IdP certificate validity window (#9077) by @LauraBeatrisAdd an experimental clerkClient.emails.create() method for sending transactional emails. It accepts address- or user-based recipients, supports optional replyTo, subject, and HTML and/or text content, and returns the created Email resource. (#9010) by @cbnsndwch
This method is marked @experimental and may change in a future release.
clerkClient.oauthApplications.revokeToken() for revoking opaque OAuth application access and refresh tokens. (#9040) by @jfosheeorganizations.deleteOrganization() now validates that an organization ID was provided. Calling it with an empty ID throws A valid resource ID is required. locally instead of issuing a DELETE request to the organizations collection endpoint, matching the other ID-based methods on the API. (#9036) by @jacekradko
M2M JWT verification now validates the token-category (cat) header and rejects M2M JWTs tagged as a different token class. M2M JWTs minted by Clerk carry the correct category and are unaffected; M2M JWTs without the header continue to verify. (#9038) by @wobsoriano
Updated dependencies [4306146, 533f0b1]:
Add an optional externalAccountId to the backend ExternalAccount resource. For Google and Facebook accounts the resource id is the idn_-prefixed identification id, which users.deleteUserExternalAccount() rejects; externalAccountId now exposes the eac_-prefixed id those calls expect. For all other providers id is already the eac_ id and externalAccountId is undefined, so use externalAccountId ?? id to get an id you can delete with. (#8995) by @jacekradko
Updated dependencies [cb76aa2]:
19ce04a]:
c38d853, 7e3174a, 97039bb, f43071d, 0e0ff11, 0039618, a536a0d]:
01789b4]:
preferredSignInStrategyWhenPasswordRequired parameter to clerkClient.instance.update(). Accepts 'password' or 'otp' to override the preferred sign-in strategy when a password is required, or an empty string to clear the override. (#8878) by @dmoernerf4167ec, 17e4164, ed2cf75, 67c04a4, 51c8fdc, c2ba971, 8744728, d9b5c7d]:
Add clerkClient.organizations.replaceOrganizationMetadata(organizationId, params) for replacing an organization's metadata fields in full. (#8787) by @brunol95
Use replaceOrganizationMetadata when the provided metadata should become the complete value for that metadata field:
await clerkClient.organizations.replaceOrganizationMetadata(organizationId, {
publicMetadata: { plan: 'pro' },
});
Use clerkClient.organizations.updateOrganizationMetadata(organizationId, params) when you want to partially update metadata with deep-merge semantics:
await clerkClient.organizations.updateOrganizationMetadata(organizationId, {
publicMetadata: { onboardingComplete: true },
});
The publicMetadata and privateMetadata parameters on clerkClient.organizations.updateOrganization() are now deprecated. They continue to work, but new code should use updateOrganizationMetadata() for partial updates or replaceOrganizationMetadata() for full replacement.
Add clerkClient.users.replaceUserMetadata(userId, params) for replacing a user's metadata fields in full. (#8587) by @brunol95
Use replaceUserMetadata when the provided metadata should become the complete value for that metadata field:
await clerkClient.users.replaceUserMetadata(userId, {
publicMetadata: { plan: 'pro' },
});
Use clerkClient.users.updateUserMetadata(userId, params) when you want to partially update metadata with deep-merge semantics:
await clerkClient.users.updateUserMetadata(userId, {
publicMetadata: { onboardingComplete: true },
});
The publicMetadata, privateMetadata, and unsafeMetadata parameters on clerkClient.users.updateUser() are now deprecated. They continue to work, but new code should use updateUserMetadata() for partial updates or replaceUserMetadata() for full replacement.
Migrate the build pipeline to tsdown and TypeScript 6.0. This is an internal tooling change with no intended changes to the public API or runtime behavior. (#8177) by @dstaley
Updated dependencies [f046c49, b5fa9f6, 3d5b2fe]:
a5c7bc7]:
createClerkClient() now exposes: (#8774) by @dmoerner
organizationPermissions — list, get, create, update, and delete organization permissions.organizationRoles — list, get, create, update, and delete organization roles, plus assign/remove a permission to/from a role.roleSets — list, get, create, update, add roles to, replace a role in, and replace a role set.Fix the return type of clerkClient.organizations.createOrganizationInvitationBulk() to PaginatedResourceResponse<OrganizationInvitation[]>. The Backend API returns the bulk-created invitations in a { data, totalCount } envelope (the same shape as getOrganizationInvitationList()), but the method was typed as OrganizationInvitation[], which did not match the value returned at runtime. (#8751) by @VihAMBR
Return IdPOAuthAccessToken timestamps in milliseconds when an OAuth access token is verified as a JWT. The expiration, createdAt, and updatedAt fields were previously populated with the JWT's raw second-based exp/iat values, making them inconsistent with the same fields on M2MToken and with the values returned when the token is fetched from the API. Comparing expiration against Date.now() now behaves as expected. The expired flag was already computed correctly and is unaffected. (#8771) by @jacekradko
Prevent an unhandled exception when verifying a machine token whose JWT payload has a missing or non-string sub. Such tokens are now classified and rejected with a typed verification error instead of throwing, so a crafted Authorization header can no longer surface as an unhandled error during request authentication. (#8744) by @jacekradko
Redact raw bearer credentials from the auth object's debug output. The debug payload (surfaced when an SDK enables middleware debug logging) previously included full session, machine, refresh, dev-browser and handshake tokens; each now exposes only a short, non-reconstructable prefix, matching how secretKey and jwtKey are already handled. (#8744) by @jacekradko
Add and improve JSDoc comments across public types and methods to support generated reference documentation for the /objects docs section. Exports a few previously-internal types (OnEventListener, OffEventListener, ClerkOptionsNavigation) so they can be referenced from the generated docs. (#8276) by @alexisintech
Updated dependencies [2d6670c, af706e3, 032632c, 0fece6f, b295af3, 8e1bd48]:
users.replaceUserEmailAddress(userId, { emailAddress }) replaces all of a user's email addresses with a single verified, primary email address (PUT /users/{user_id}/email_address).users.replaceUserPhoneNumber(userId, { phoneNumber }) replaces all of a user's phone numbers with a single verified, primary phone number (PUT /users/{user_id}/phone_number).users.createUser now accepts banned and locked parameters to create a user that is already banned or locked.Emit the "session token from cookie is missing the azp claim" warning once per process instead of on every authenticated request. An azp-less cookie token is reused across requests, so the previous unguarded console.warn could flood production logs. (#8698) by @jacekradko
Stop authenticateRequest from consuming the incoming request body, which previously left downstream handlers unable to read it (for example a Hono POST route calling c.req.json()). (#8708) by @jacekradko
Prevent keyless mode from activating in CI and other automated environments in framework SDKs. (#8676) by @mwickett
Preserve custom claims when verifying JWT-format M2M tokens. M2MToken.fromJwtPayload previously hardcoded claims to null, so client.m2m.verify() (and request-level auth()) dropped any custom claims embedded in the token. Custom claims are now reconstructed from the verified payload by stripping only the structural claims the backend adds when minting the token (iss, sub, exp, nbf, iat, jti). User-supplied claims such as aud are preserved. Tokens without custom claims still return claims: null, consistent with the opaque-token path. (#8697) by @jacekradko
Strip private_metadata from the backend resource _raw payload in stripPrivateDataFromObject, preventing it from leaking into __clerk_ssr_state when a User/Organization resource is passed to buildClerkProps. (#8702) by @dominic-clerk
Updated dependencies [afb75e6, c3df67a, 86fd38f, 8d6bb56, 43dfefa, 5fc7b21, c2ba134]:
a036ce8]:
Adds agentTaskId and deprecates taskId to Agent Tasks Create response. (#8013) by @tmilewski
Updated dependencies [95f6c2f]:
4fc38a0]:
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]: