Repository navigation
fix(magic-link): issue one session per link, and confirm links opened on another device - #449
Merged
Merged
Conversation
…ested it Bind each magic link to the requesting ephemeral token's jti and redeem it once. Later checks for the same attempt are told the sign-in is complete without receiving another session.
…r device Verify consumes the link only on the requesting device, proven by the attempt's ephemeral token when the adapter forwards it, otherwise by IP and user agent. Elsewhere it answers 409 confirmation_required without consuming the link, and POST /magic-link/verify/:token/confirm consumes it once the person who opened it approves.
5 of 36 tasks
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.
Fix for GHSA-9jg2-jjqq-3346. Reviewed privately in the advisory fork.
What changes
jti.GET /magic-link/checkonly finds links for the polling attempt, and issues the session once (redeemed_at, set atomically). Later checks for the same attempt get200 { message: 'Success' }without tokens, so a second tab in the same browser still completes from the cookie it already has.GET /magic-link/verify/{token}consumes the link only on the requesting device: a forwarded ephemeral bearer whosejtimatches, otherwise the IP and user agent a trusted adapter forwarded with its service token. Anywhere else it answers409 confirmation_requiredwith the requesting platform and time, and leaves the link unused. Mail scanners and links someone else requested no longer complete a sign-in.POST /magic-link/verify/{token}/confirmconsumes the link after the person who opened it approves.magic_link_confirmation_required. Migration addsattempt_id,requested_device_classandredeemed_at.Checks
npm run coverage: 136 files, 1826 passed, 1 todo. Statements 98.91%, branches 95.38%, functions 99.27%, lines 99.15%Ripple (not in this PR)
All adapters (Express, Fastify, Next.js, Go, Python, Rust) pick up the confirm route from the manifest. Each needs to forward the browser's pre-auth credential on verify (optional, never 401). The client needs
confirmMagicLinkand apreAuthidentity on verify; the React, Angular, Vue and Svelte verify screens need a confirm step; types, docs and the Next.js template follow. Old SDKs show the 409 as an error, so cross-device links fail closed until they upgrade; same-device links keep working.Part of the v0.19 security release (#385). Rebased onto main after #440 to #446; 138 files, 1870 tests pass locally.