feat(auth): Login with Thingtime anywhere — federated hints, SSO handoff, FedCM IdP - #327
Conversation
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 36358199 | Triggered | Generic Password | b68fb94 | remix/scripts/verify-federated-login.mjs | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
3227349 to
18b6c56
Compare
|
🤖 Auto-rebase running — the stack rebase started working on this PR at 09:23 UTC. Expected to finish around 09:38 UTC (most rebases still land in 5-15 minutes; the hosted-runner ceiling is 360). On success this branch is force-pushed onto its new base and a result comment follows — no manual action is needed meanwhile. |
…off, FedCM IdP Extends #323's auto-login beyond the *.thingtime.com cookie family while honoring the owner's constraint end to end: quick-login is powered by the sessions in the USER'S BROWSER, federated per deployment — never a central session store. thingtime.com is only a broker reading the browser's own tt_hints cookie and its own switcher roster. Layer 1 — federated hint resolution (multi-database environments): account-hints reports foreign-DB origins as 'unresolved'; the new GET /api/v1/auth/account-hints/resolve (CORS-credentialed, Thingtime family only, read-only) lets each environment vouch for exactly the pointers its origin wrote; useAccountHints fans out (cap 4) and merges by user id. The browser assembles the full picture. Layer 2 — cross-origin session handoff: POST /auth/sso-handoff mints a 2-minute, aud-bound, single-use code (purpose-fenced JWT backed by a pre-minted session that self-expires unclaimed); the receiving deployment's POST /auth/sso-session verifies signature + aud === its own public origin, claims atomically once (replay revokes — theft signal), then runs the exact password-login tail. Different-environment redemption fails closed. UI: /authorize?self=1 popup (embedded login with hints strip when signed out, "Continue to <host>?" card when signed in) and a "Sign in with Thingtime" card on foreign origins. Layer 3 — FedCM IdP: /.well-known/web-identity + config/accounts/ client-metadata/assertion endpoints; Sec-Fetch-Dest: webidentity enforced; accounts = this browser's own roster (anti-fixation gate intact — only redeemable sessions are offered); assertion mints handoff codes for thingtime-self or baseline-profile app tokens for registered clients; the foreign-origin card prefers the native sheet via IdentityCredential feature-detect. Verified: scripts/verify-federated-login.mjs 31/31 against two stacks on SEPARATE mongods (recipe + its two sharp edges documented in the script header: stack B must be a production build — nitro dev dotenv re-overrides .env on config reloads — and a second mongod, because the home db name is pinned to 'thingtime'). verify-passkeys.mjs still 44/44. Browser-verified both /authorize?self=1 states. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Refreshed by the rebase-pr-stacks workflow: https://github.com/lopugit/thingtime/actions/runs/32237322814
6909b76 to
c232535
Compare
|
🧬 Rebased
The branch was published once with an exact force-with-lease. Please review the rewritten commits before relying on them. |
Stacked on #323 (passkeys + cross-deployment auto-login) — merge that first; this diff is the federation layers only. Full architecture note: PRs/login-with-thingtime-anywhere.md.
Owner's design constraint, honored end to end: quick-login is powered by the sessions in the user's browser, federated per deployment — never a central session store. thingtime.com acts only as a broker reading the browser's own
tt_hintscookie and its own switcher roster; every deployment vouches exclusively for its own sessions.🌐 Layer 1 — Federated hint resolution (multi-database environments)
/api/v1/auth/account-hintsnow reports foreign-database origins asunresolved; the client fans out (cap 4) to each origin's new/api/v1/auth/account-hints/resolve— CORS-credentialed for the Thingtime family only, resolves only pointers its own origin wrote, read-only (never prunes, never sets cookies). The browser assembles the full cross-environment picture.🔁 Layer 2 — Cross-origin session handoff
For Thingtime deployments outside the cookie family (immutable
*.vercel.apppreviews, custom domains):POST /auth/sso-handoff(signed-in): mints a 2-minute, aud-bound, single-use code backed by a pre-minted session that self-expires unclaimed.POST /auth/sso-session(receiving deployment): signature +aud === own public origin(origins stay default-open — per-code binding is the security, per the PR Thingtime SSO: default-open origins — any URL (incl. preview deploys) can use Login with Thingtime #87 decision), atomic single claim — replay revokes the session (theft signal) — then the exact password-login tail (cookies, roster merge, hints pointer). Different-environment redemption fails closed./authorize?self=1popup — embedded login with the hints strip when signed out, "Continue to ?" confirm card when signed in; foreign origins get a "Sign in with Thingtime 🌈" card in place of the hints popup.✨ Layer 3 — FedCM identity provider
/.well-known/web-identity→ config → accounts / client-metadata / assertion. The browser (never the page) fetches accounts with first-party cookies and draws its native "Continue as…" sheet on any domain;Sec-Fetch-Dest: webidentityis enforced so page JS can't read the endpoints. Accounts = this browser's own switcher roster (anti-fixation gate intact — only redeemable sessions are offered). Assertions mint handoff codes (thingtime-self) or baseline-profile app tokens (registeredttapp_…clients; wider grants still require the consent popup). The client feature-detectsIdentityCredentialand prefers the native sheet, popup as the everywhere-fallback.🧪 Verification
verify-federated-login.mjs— 31/31 against two stacks on separate mongods — per-environment authority, CORS allow/deny, handoff aud-binding + cross-environment fail-closed + replay-revokes, and the complete FedCM accounts→assertion→session loop. The script header documents the recipe and its two sharp edges (stack B must be a production build — nitro's dev dotenv re-overrides.envon config reloads — against a second mongod, because the home db name is pinned tothingtime).verify-passkeys.mjsstill 44/44; lint clean; browser-verified both/authorize?self=1states (screenshots in comments).remix/CHANGELOG.mdupdated.🤖 Generated with Claude Code