Repository navigation
feat(checkout): /claim/<token> page for guest buyers, magic link + passkey sign-in - #124
Merged
Merged
Conversation
…sskey sign-in A paid guest checkout emails a /claim/<token> link, but no page existed, so a guest who paid could not get the episode. - /claim/<token>: asks the API what the link is, then attaches the purchase to the signed-in account, or signs the buyer in or up by emailed magic link (prefilled with the payment email) or passkey and finishes the claim on return (?auto=1), polls until the worker grants the entitlement, and opens /play?mode=campaign&episode=<id>. - Clear states for used, expired, pending, refunded and forged links, with a "send me a fresh link" form (by old link or by payment email; same answer either way, mail only goes to the address that paid). - API: POST /checkout/claim/status, POST /checkout/claim/resend; POST /checkout/claim now refuses dead links with a code (409/410/400) instead of queueing them, and answers 200 + playUrl when it is already yours. Tokens travel in POST bodies, never URL paths. - entitlements: describeClaim + readClaimTokenIgnoringExpiry (pure, tested). - auth: Better Auth magic-link and passkey plugins (house auth); accounts created that way get a generated display name. passkeys table, migration 0001_passkeys (applied to prod). Login page offers link + passkey first; account page can add a passkey. - Worker: magic-link email; claim email says the link lasts 7 days. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ThreatCrush Security Scan1 finding(s) MEDIUM: 1
Snippets are redacted; ThreatCrush never prints matched credential material. |
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.
Paid guest checkouts (#122/#123) email a
/claim/<token>link, but there was no page behind it, so a paying guest could not get the episode.What
/play?mode=campaign&episode=<id>.POST /checkout/claim/statusandPOST /checkout/claim/resend.POST /checkout/claimnow refuses dead links with a code (409/410/400) and answers 200 with playUrl when the purchase is already yours. Tokens go in POST bodies, never URL paths, so they stay out of access logs.user_id is null).passkeystable, migration0001_passkeys(already applied to prod; additive). The login page now offers link and passkey first, and the account page can add a passkey.Tests
bunx vitest run: 45 files, all pass (new: describeClaim, API claim/status/resend, display-name defaults, claim page copy). typecheck and eslint are clean./claim/<token>?auto=1, claim 202, worker,claimed_by_you, entitlement active. Re-claim answers 200 + playUrl, and a stranger sees "claimed".🤖 Generated with Claude Code