Feature: paid posts slice 3, patron link + passkey (cookie-less)
The registration leg of the paid-posts flow (klonkt-demo-aki). A
visitor links once via Patreon and gets a pseudonymous passkey entitlement,
with no session and no patron identity stored.
- Dependency (approved): @simplewebauthn/server for verification, plus
@simplewebauthn/browser vendored (UMD) so the page loads it with no CDN.
- New paid_entitlements table: {passkey, site, proven cents, expiry}. No
name, e-mail or Patreon id, ever.
- Cookie-less throughout: the OAuth state and the WebAuthn challenge
travel in signed blobs (CryptoBox), so nothing is kept between requests.
- Flow: GET /paid/link -> Patreon authorize; GET /paid/callback verifies
the patron (verifyPatron exchanges the code, reads
identity?include=memberships.campaign, checks patron_status +
currently_entitled_amount_cents against the post's price), then hands out
registration options + a signed blob carrying the challenge and proven
cents; POST /paid/register verifies the passkey and stores the
entitlement. The patron token is used once and discarded.
The gate button and the per-post unlock (assertion) are slice 4; this
leg is what that flow calls to register a passkey on demand.
Changed files:
package.json, package-lock.json
- @simplewebauthn/server + @simplewebauthn/browser
src/assets/vendor/simplewebauthn-browser.umd.min.js
- vendored browser UMD (no CDN)
src/config/database.js
- paid_entitlements table (no patron identity)
src/services/PaidPatreonService.js
- pickCampaignMembership (pure), verifyPatron (exchange + identity)
src/server.js
- mount /paid before the /:slug catch-all
New file:
src/services/PasskeyService.js
- registration options + verify (lib) + entitlement store/prune
src/routes/paid.js
- link / callback / register (cookie-less)
src/views/pages/paid-passkey.ejs, paid-result.ejs
- passkey creation + not-a-supporter pages
test/paid-patron.test.js
- membership parse, patron exchange (mock), options challenge,
entitlement store/expiry/prune/delete, no-identity-columns
-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>