better-auth stores OAuth state in verification for 10 minutes. It deletes an expired row only when a later lookup touches that row. A claim sign-in nobody finished keeps callbackURL: /claim/<secret> with the raw claim secret, so on a quiet instance that secret stayed in the table indefinitely.

An hourly Inngest cron, sweep-expired-verifications, now deletes every verification row past its expiresAt. better-auth never reads an expired row except to delete it, so the sweep removes all expired rows, not only claim ones. The cron uses the same shape as prune-organization-change-log: concurrency 1 and 3 retries. It is registered in inngest/index.ts and pinned in policies.test.ts.

Bets

None.

Tests

verification-sweep.server.postgres.test.ts seeds an expired claim row, an expired sign-in row and a live claim row. After the sweep only the live row remains. The test fails on main (the module is missing), and it also fails against a no-op sweep, which proves the assertion catches a sweep that deletes nothing. It passes here.

Checks

11 successful Β· 6 skipped
All checks passed
aa72236
Synced from GitHub

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

ReviewStatusCommitReview trigger
πŸ“ Code Review⚠️ Failed 2026-10-17T13:52:19.345506Zf5842a3PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with πŸ‘€ while any review is running, comments if it has suggestions, and reacts with πŸ‘ once all reviews finish with no findings.

Synced from GitHub

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Synced from GitHub

Review in Change Stack β†’

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

βš™οΈ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 94d3a85a-8b28-4597-892d-b30b00e89333
πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between c223011bad44e97a0ff28083ad734b8e9b39bf54 and aa72236ae4fdf37737eeef74bfdeaeed4644f7e4.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • πŸ” Trigger review

No actionable comments were generated in the recent review. πŸŽ‰

ℹ️ Recent review info
βš™οΈ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: efc8a7ff-27ff-49d6-ade6-8e72a2fa44a4
πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between dd65cd5b1eb3e6081bea9a572bcb31759052c22b and f5842a3b719abfc599d97851419525d48b1f6959.

πŸ“’ Files selected for processing: 5
  • dashboard/src/modules/identity/verification-sweep.inngest.ts
  • dashboard/src/modules/identity/verification-sweep.server.postgres.test.ts
  • dashboard/src/modules/identity/verification-sweep.server.ts
  • dashboard/src/modules/inngest/index.ts
  • dashboard/src/modules/inngest/policies.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.

πŸ“ Summary

Summary by CodeRabbit

  • New Features
    • Expired verification records are now cleaned up automatically every hour, while records that have not expired are retained.

Adds a database operation that deletes expired verification rows. Registers an hourly Inngest function to run the operation, with three retries and concurrency limited to one. Adds a live database test and policy contract coverage.

Changes: Expired verification sweep

Layer / File(s)Summary
Delete expired verification rows
dashboard/src/modules/identity/verification-sweep.server.ts, dashboard/src/modules/identity/verification-sweep.server.postgres.test.ts
Adds sweepExpiredVerifications, which deletes rows whose expiresAt is earlier than the database’s current time and maps deletion errors to VerificationSweepFailure. The database test checks that expired rows are removed and a future-expiring row remains.
Schedule and register the sweep
dashboard/src/modules/identity/verification-sweep.inngest.ts, dashboard/src/modules/inngest/index.ts, dashboard/src/modules/inngest/policies.test.ts
Adds an hourly Inngest function with three retries and concurrency limited to one. Registers the function and adds its retry and concurrency settings to the policy contract test.

Priority: βž– Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Sequence Diagram(s)

mermaid
1sequenceDiagram
2 participant Inngest
3 participant SweepFunction as createSweepExpiredVerifications
4 participant EffectRunner as runInngestEffect
5 participant VerificationSweep as sweepExpiredVerifications
6 participant Database
7 Inngest->>SweepFunction: hourly trigger
8 SweepFunction->>EffectRunner: run named sweep step
9 EffectRunner->>VerificationSweep: execute sweep Effect
10 VerificationSweep->>Database: delete rows where expiresAt < now()
Merge Risk: βšͺ Minimal Β· up to f5842

This adds an hourly cleanup of expired verification rows, so unfinished claim sign-in secrets no longer linger in the table. No merge-blocking risk was found.

Security architecture risk: πŸ”΅ Low Β· up to f5842

The cleanup is restricted to expired records and uses the existing background worker without adding credentials or a public execution route. No introduced security defect was established. Some authentication-library behavior and scheduler rollback behavior remain unverified.

Retained concerns No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed β€” The added deletion capability covers all expired verification records in the configured dashboard database, not only claim-related rows or a single tenant. Its SQL operation does not target refresh-token tables or other data stores.

Trust Boundaries and Controls

  • observed β€” The existing claim-binding consumer deletes by the exact user-and-secret-derived identifier and accepts only an unexpired returned binding. The unchanged MCP path requires a request-bound consent grant when issuing organization-bearing claims, providing counterevidence against cleanup of a missing code becoming an authorization bypass.

Resilience and Maintainability Implications

  • inferred β€” For claim-binding consumption, concurrent cleanup either removes the expired row first or leaves consumption to delete and expiry-check it; neither ordering selects another user's binding. Complete verification-consumer compatibility remains unresolved because the MCP lookup delegates expiry enforcement to the external authentication provider, while claim validation and cleanup use different clocks.
Pre-merge checks: Passed 4 Β· Failed 1

Failed Failed checks: 1 warning

Check nameStatusExplanationResolution
Docstring CoverageWarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 5 files.Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main change: an hourly sweep of expired verification rows.
Description checkPassedThe description explains the motivation, implementation, registration, policy settings, and database test for the verification-row sweep.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches: πŸ’‘ 1
πŸ“ Generate docstrings: πŸ’‘
  • Commit to this branch
  • Create a new PR
πŸ§ͺ Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix Β· Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Added 1 commit

  • Sweep expired verification rows every houraa72236