feat(js): attach an optional server-configured session token to sign-in - #9299
Draft
zourzouvillys wants to merge 1 commit into
Draft
feat(js): attach an optional server-configured session token to sign-in#9299zourzouvillys wants to merge 1 commit into
zourzouvillys wants to merge 1 commit into
Conversation
Mints an opaque, random correlation id and acquires a signed Protect session token once per browser session, shared across tabs under a lock. The token, the correlation id and an acquisition status travel in the form-encoded body of sign-in and sign-up POSTs. Acquisition never blocks a sign-in: on timeout, script-load failure or a non-2xx response a structured status travels in the token's place and the request proceeds. Instances whose loader config does not reference the new placeholders keep today's behaviour and store nothing in the browser.
🦋 Changeset detectedLatest commit: de9b78e The changes in this PR will be included in the next version bump. This PR includes changesets to release 23 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 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-google-signin
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
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.
Description
Adds an optional, server-configured session token to
@clerk/clerk-jsthat is attached to sign-in and sign-up requests.What this adds:
crypto.getRandomValues, lowercase unpadded RFC 4648 base32. One half persists atlocalStorage["__clerk_protect_pid"], the other is per-run. Nothing is derived from the device — no fingerprint input, no clock, no user data.Protect.applyLoader. A closed set —{cid},{pid},{rid},{instance_id}— substituted into loader attribute values before they are set. An unrecognised{…}is left verbatim, so an older SDK that does not interpolate stays compatible with the same config.SafeLock(core/auth/safeLock.ts), the same primitiveSessionCookiePolleruses, with the result inlocalStorage["__clerk_protect_st"]. Read the store → if valid and not near expiry, use it with no lock and no network → otherwise take the lock → re-read inside the lock → still absent, acquire → write → release. The re-read is what stops N tabs each acquiring in turn, and it is tested directly. Waiters abort onSafeLock's own signal so a wedged leader delays nobody; a leader tab closing mid-run releases its Web Lock automatically and a waiter picks up what it wrote.Clerk.load(), not at sign-in, so the token is normally cached long before a user submits credentials. One attempt per page load, so a failure is not re-paid by every subsequent sign-in.__clerk_protect_token/__clerk_protect_status/__clerk_protect_cidin the form-encoded body of sign-in and sign-up POSTs. Not the query string — a signed credential should not land in access logs along the path. Not a header — a custom header reintroduces the CORS preflight that breaks cookie dropping in Safari, the same constraint that already forces_methodinto the query. No request header is added anywhere. This is an explicit merge step infapiClient.requeston a path allowlist, because theonBeforeRequestcallbacks fire after the body is stringified.ok|timeout|script_error|fetch_error|http_<n>|unsupported. The field is always populated; the request never blocks — on any failure the status travels in the token's place and the sign-in proceeds.Judgement calls worth a reviewer's attention
srckeeps exactly today's behaviour, stores nothing in the user's browser and sends no params.ProtectLoadergains two optional fields,tokenUrlandtokenTimeoutMs. WhentokenUrlis absent it is resolved against the loader URL carrying the{cid}. Configurations that cannot be derived must settokenUrlexplicitly. Keeping the URL shape in instance config is deliberate. Nothing server-side sets these fields yet; they are inert until it does.{instance_id}resolves from a field the server does not currently send, so today it is left verbatim. It starts working the moment that field is populated — no SDK change needed.unsupportedis reserved for "cannot mint at all" (nocrypto.getRandomValues). WhenlocalStorageis unavailable we fall back to an in-memory value for the page lifetime and keep going — losing cross-tab sharing but not the sign-in. Reportingunsupportedfor a run that actually succeeded would be a lie.pnpm bundlewatch:fix.rolloutmoved out ofapplyLoaderinto a module-level helper soload()can decide participation before it starts applying loaders. Same semantics, evaluated once.Testing
packages/clerk-js: 66 files, 971 tests green. New coverage: base32 against the RFC 4648 vector, id shape and length, persistence across runs, thelocalStorage-throws fallback, the in-lock re-check proving one acquisition for two concurrent tabs (with a serialising Web Locks stand-in, since jsdom has none and thebrowser-tabs-lockmock always grants), every status path, placeholder interpolation including the unrecognised and no-value cases, and body-param attachment on the allowlisted paths only.tsc,eslint,prettierandbundlewatchclean.Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change