Repository navigation
Require verified sign-in and queue verification delivery - #67
Merged
Merged
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This was referenced Nov 6, 2026
Require email verification before sign-in and preserve offline account data
PapyrusReader/client#134
Merged
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.
Registration now commits a pending account and a durable verification email job without creating a session. Password login, Google exchange, refresh, shared API authentication and explicit deletion recovery require evidence for the current primary email. Existing verified sign-in retains the AuthTokens response and refresh rotation.
Closes #22. Implements TASK-AUTH-02 for FR-1_1, FR-1_2 and FR-1_3, following the accepted TASK-AUTH-01 contract merged in PapyrusReader/docs#93. Client integration remains PapyrusReader/client#60.
Behavior
PendingVerificationResponse. Missing SMTP/landing configuration or a failed queue transaction returnsVERIFICATION_UNAVAILABLEwithRetry-After: 60and rolls back pending account data./verify-email. Tokens are hashed for lookup, bound to the exact email, single-use and valid for 24 hours. Confirming one link consumes all outstanding links for that address without signing in or cancelling deletion.no-store.email_verified=truewith a nonempty signedhd. The subject remains the identity key. Primary-email matching, existing-account conflicts and explicit linking remain enforced. Pending handoffs are consumed with HTTP 403 even if verification completes before exchange. Verified Google sign-in works without SMTP.Database model
The account stores
primary_email,email_verified_atandemail_verification_source. The publicemail_verifiedboolean is derived, with a database constraint requiring complete, valid evidence. There is no second account email, persisted verification boolean or duplicated provider subject. Google subjects and validated hosted-domain claims remain on the linked identity records.Existing-email changes use one owner-locked transaction to clear evidence, invalidate email tokens and OAuth/recovery codes, cancel queued verification mail, and revoke sessions. Normalized no-op changes retain access. Rollback preserves the original state, and changing away and back cannot revive old links. Credential revocation is shared with deletion/recovery.
Verification delivery rows store only the token reference, deliverable secret and retry state. Owner, recipient and expiry come from the token row. Token address binding, the shared recipient cooldown, and the separate lifecycle-notice queue remain necessary for their distinct security and ordering rules.
Migration and activation audit
d1e2f3456789followsc0d1e2f34567and adds verification evidence, token address binding, hosted-domain claims, cooldowns and the outbox. The follow-upd2f3456789abremoves the redundant fields and adds the evidence constraint. The prior migration remains intact so databases that already applied it can upgrade safely. Both preserve user IDs, password hashes, linked identities, libraries, reading positions and pending deliveries.The exact predicates retained as evidence are password-only Papyrus verification or a matching retained Google Gmail identity. The combined eligibility predicate is:
Google subjects remain on linked identity records, and account evidence refers to the current primary email. Workspace authority is never inferred from old provider booleans or domain strings. Previously true accounts outside this predicate require fresh proof. Their boolean is cleared and their sessions are revoked. Existing unverified sessions are also revoked, and old unbound verification tokens are consumed. The migration logs the affected previously-verified account count without account identifiers. The seeded migration regression reports 2 affected accounts out of 5, preserves the password-only and attributable Gmail verified accounts/sessions and all credentials, identities and library state. A fresh isolated migration database reports 0. These are local validation counts, not a production audit. Before activation, record the actual deployment count using
SELECT count(*) FROM users WHERE primary_email_verified = true AND NOT (<predicate above>), and retain the migration log. Downgrade is deliberately refused because rollback must preserve enforcement and evidence.Validation
tools/papyrus check serverpassed: Ruff lint, formatting and strict Mypy. The CLI functions were directed at the isolated server worktree without changing workspace component paths.papyrus_auth22_testdatabase. Database suites ran serially under the workspace test lock.d1e2f3456789database tod2f3456789abandalembic checkpassed with no schema drift. The populated regression preserves verification timestamps, queued secrets/expiry/retry state and durable library data, clears stale evidence, and checks queue access restrictions.--checkpassed. CI now publishesserver-openapi-<sha>using the existing exporter. The coordinated docs change should consume this artifact and pin.github/workflows/ci.yml's server revision to the accepted server commit. No manual/requirements/static documentation was changed here.src/lib/{api,config,dom,jwt,html,storage}. Onlyfeedback.tsis tracked there. This pre-existing developer-tool build gap is separate from backend validation.Deployment order and client #60
EMAIL_VERIFICATION_TOKEN_EXPIRE_MINUTES=1440.d2f3456789aband deploy the enforcing server through the normal development-to-master release process. Do not leave older instances granting unverified sessions. Keep queue-table access restricted to the application/migration owner and privileged operators.No merge or deployment is part of this PR preparation.