Repository navigation
Conversation
assertExpirationClaim compared a Date built with setUTCSeconds(exp). For a finite exp outside the Date range, such as -1e300, that Date is invalid, the comparison is NaN, and an expired token passed. Compare numeric seconds instead, keeping the existing truncation, skew and error messages, and apply the same fix to nbf and iat. Nonfinite time claims are rejected as invalid. Refs AIE-2068
The machine OAuth JWT path called verifyJwt without an issuer, so a token signed by a resolved key was accepted whatever its iss. Require iss to equal the instance's Frontend API URL from the publishable key, the same authorization server the SDKs advertise in resource metadata. The session-token issuer option is still ignored for machine tokens, and M2M JWTs are unchanged. Refs AIE-2073
…JWT test helpers Pass resolveKeyAndVerifyJwt's headerType and issuer as one options object, declare the machine-token publishableKey option once, share the seconds to milliseconds conversion in the time claim assertions, and consolidate the OAuth and session JWT test helpers and Date-limit constant.
resolveKeyAndVerifyJwt rewrapped every key-loading failure as token-verification-failed, so an invalid secret key on the JWKS call lost its secret-key-invalid reason and a JWKS outage looked like a bad token. Keep secret-key-invalid, and report a thrown JWKS fetch, a non-2xx JWKS response or an unreadable error body as the new jwk-remote-failed-to-load machine error code. Signature, claim and kid failures keep token-verification-failed.
Only a failure of loadClerkJWKFromRemote now maps to the remote key-loading reasons. An unexpected error from the local jwtKey path or verifyJwt keeps token-verification-failed, as before the key-loading change.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 78af740 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
|
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-biometrics
@clerk/expo-google-signin
@clerk/expo-native-components
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/mosaic
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
wyattjoh
added a commit
to clerk/mcp-tools
that referenced
this pull request
Nov 14, 2026
…ent Hono's cors() interaction No @clerk/backend release reports jwk-remote-failed-to-load yet, so the comments cite the PR that adds it, and the prefix rule is dropped once the supported backend floor reports the reason. Behind Hono's cors() middleware, the metadata GET keeps the headers cors() sets: cors() writes them to c.res, and Hono's res setter copies them over the handler's response. A test pins this; the README and changeset say so, unlike Express, where the handlers' headers win.
wyattjoh
added a commit
to clerk/mcp-tools
that referenced
this pull request
Nov 14, 2026
…r the JWKS reason No @clerk/backend release reports jwk-remote-failed-to-load yet (3.29.0 still maps JWKS failures to token-verification-failed), so the READMEs and changeset describe current releases and say what changes once clerk/javascript#10826 ships.
1 task
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
@clerk/backendgets stricter machine JWT verification. Expired and not-yet-valid tokens are rejected even when a time claim is beyond the range a JavaScriptDatecan represent, OAuth access token JWTs must carry the instance's issuer, and a JWKS loading failure on a machine JWT now reports why the key couldn't load instead oftoken-verification-failed.Why
authenticateRequest()andverifyMachineAuthToken()accepted some tokens they should reject and misreported some failures. An expired token passed when itsexpwas outside the range a JavaScriptDatecan represent, such as-1e300. An OAuth access token JWT signed by a resolved key passed whatever itsiss. When the JWKS couldn't load, callers such as@clerk/mcp-toolsgottoken-verification-failed, as for a bad signature, and told MCP clients to discard tokens Clerk never checked.How
Datebuilt withsetUTCSeconds. An invalidDatemade the comparisonNaN, so the check passed. The existing truncation and clock skew are unchanged. The same fix coversnbfandiat, and claims that aren't finite numbers are rejected as invalid (RFC 7519 §4.1.4). Values beyond theDaterange are only rejected when they are expired or not yet valid: a far-futureexpor a far-pastnbf/iatstill passes.Infinity,-1e+300) when it can't be shown as a date, instead ofInvalid Dateornull.issexactly equal to the Frontend API URL derived from the publishable key, even when a proxy URL is configured, because the Frontend API issues the token (AIE-2073). RFC 9068 §4: "The issuer identifier for the authorization server (which is typically obtained during discovery) MUST exactly match the value of the "iss" claim." The session-tokenissueroption still doesn't apply to machine tokens, and M2M JWTs and opaque tokens are unchanged.verifyMachineAuthToken()fails closed: an OAuth access token JWT is rejected withtoken-verification-failedbefore any JWKS fetch when no validpublishableKeyis passed, since the expected issuer can't be derived.authenticateRequest()already requires a valid publishable key, so its behaviour is unchanged.secret-key-invalidfor an invalid secret key. A thrown fetch, a non-2xx response or an unreadable error body now reports the newMachineTokenVerificationErrorCode.RemoteJWKFailedToLoad(jwk-remote-failed-to-load). Signature,kidand claim failures, and unexpected errors outside the remote load, still reporttoken-verification-failed.minor: the PR adds an exported error code and a new rejection forverifyMachineAuthToken()callers that don't pass a publishable key, which consumers may need to handle when upgrading.resolveKeyAndVerifyJwttakesheaderTypeandissueras one options object, and the machine JWT test helpers are shared.Follow-ups
@clerk/mcp-tools(feat!: one consistent auth and tools API across the Express, Hono, and Next.js adapters mcp-tools#49), which already treatsjwk-remote-failed-to-loadas verification unavailable, can raise its@clerk/backendfloor and drop itsError loading Clerk JWKSmessage match.Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change
Part of AIE-2068