Skip to content

fix(db): support verification operations with secondary storage#8247

Merged
himself65 merged 3 commits intocanaryfrom
fix/magic-link-secondary-storage
Mar 1, 2026
Merged

fix(db): support verification operations with secondary storage#8247
himself65 merged 3 commits intocanaryfrom
fix/magic-link-secondary-storage

Conversation

@himself65
Copy link
Copy Markdown
Contributor

@himself65 himself65 commented Mar 1, 2026

Summary

Fixes #8228

When secondaryStorage is configured without verification.storeInDatabase, the verification table is excluded from the DB schema by getAuthTables(). This caused deleteVerificationValue(id) and updateVerificationValue(id) to fail with Model "verification" not found in schema because they operate by DB id, which doesn't exist in secondary-only mode.

  • Add updateVerificationByIdentifier to the internal adapter, following the existing deleteVerificationByIdentifier pattern
  • Migrate all callers across the codebase from id-based (deleteVerificationValue/updateVerificationValue) to identifier-based (deleteVerificationByIdentifier/updateVerificationByIdentifier) methods
  • Remove the now-unused id-based methods from the internal adapter and type definitions
  • Handle expiresAt as string when secondary storage returns pre-parsed objects (fixes expiresAt.getTime is not a function)

Affected plugins/modules

magic-link, email-otp, two-factor, phone-number, one-time-token, oidc-provider, mcp, siwe, oauth-provider, electron, sso, state, password, update-user

Test plan

  • New integration tests in test/unit/magic-link-secondary-storage.test.ts covering:
    • Send and verify magic link with secondary storage (string return)
    • Sign up new user via magic link
    • Track attempts and reject when exceeded
    • Delete expired verification on verify
    • Pre-parsed object return (e.g. Redis wrappers)
  • Existing magic-link tests pass (16/16)
  • Internal adapter tests pass (29/29)
  • email-otp tests pass (70/70)
  • two-factor tests pass (34/34)
  • password tests pass (16/16)
  • one-time-token tests pass (13/13)
  • Typecheck passes
  • Lint passes

@himself65 himself65 requested a review from Bekacru as a code owner March 1, 2026 11:24
Copilot AI review requested due to automatic review settings March 1, 2026 11:24
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
better-auth-demo Ignored Ignored Mar 1, 2026 0:13am
better-auth-docs Skipped Skipped Mar 1, 2026 0:13am

Request Review

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 1, 2026

Open in StackBlitz

@better-auth/api-key

npm i https://pkg.pr.new/@better-auth/api-key@8247

better-auth

npm i https://pkg.pr.new/better-auth@8247

auth

npm i https://pkg.pr.new/auth@8247

@better-auth/core

npm i https://pkg.pr.new/@better-auth/core@8247

@better-auth/drizzle-adapter

npm i https://pkg.pr.new/@better-auth/drizzle-adapter@8247

@better-auth/electron

npm i https://pkg.pr.new/@better-auth/electron@8247

@better-auth/expo

npm i https://pkg.pr.new/@better-auth/expo@8247

@better-auth/i18n

npm i https://pkg.pr.new/@better-auth/i18n@8247

@better-auth/kysely-adapter

npm i https://pkg.pr.new/@better-auth/kysely-adapter@8247

@better-auth/memory-adapter

npm i https://pkg.pr.new/@better-auth/memory-adapter@8247

@better-auth/mongo-adapter

npm i https://pkg.pr.new/@better-auth/mongo-adapter@8247

@better-auth/oauth-provider

npm i https://pkg.pr.new/@better-auth/oauth-provider@8247

@better-auth/passkey

npm i https://pkg.pr.new/@better-auth/passkey@8247

@better-auth/prisma-adapter

npm i https://pkg.pr.new/@better-auth/prisma-adapter@8247

@better-auth/redis-storage

npm i https://pkg.pr.new/@better-auth/redis-storage@8247

@better-auth/scim

npm i https://pkg.pr.new/@better-auth/scim@8247

@better-auth/sso

npm i https://pkg.pr.new/@better-auth/sso@8247

@better-auth/stripe

npm i https://pkg.pr.new/@better-auth/stripe@8247

@better-auth/telemetry

npm i https://pkg.pr.new/@better-auth/telemetry@8247

@better-auth/test-utils

npm i https://pkg.pr.new/@better-auth/test-utils@8247

commit: 832e457

When secondaryStorage is enabled without verification.storeInDatabase,
updateVerificationValue and deleteVerificationValue would fail with
"Model verification not found in schema" because they always tried to
hit the database directly.

- Generate an id for verifications stored in secondary storage only
- Store a reverse id-to-identifier mapping in secondary storage
- Add secondary storage support to updateVerificationValue
- Add secondary storage cleanup to deleteVerificationValue and
  deleteVerificationByIdentifier
- Add regression tests for magic link with secondary storage
@himself65 himself65 force-pushed the fix/magic-link-secondary-storage branch from 61b35ea to 466f876 Compare March 1, 2026 11:28
@vercel vercel bot temporarily deployed to Preview – better-auth-docs March 1, 2026 11:28 Inactive
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes verification CRUD behavior when secondaryStorage is enabled but verification.storeInDatabase is disabled, so verification updates/deletes no longer fail due to missing DB schema. It extends the internal adapter to support updating verifications by identifier and adds secondary-storage bookkeeping to support update/delete flows.

Changes:

  • Add updateVerificationByIdentifier to the internal adapter interface and implement it in the Better Auth internal adapter.
  • Introduce a secondary-storage reverse mapping (verification-id:<id><storedIdentifier>) and use it to support update/delete by id in secondary-only mode.
  • Update Magic Link verification to update/delete by identifier and add regression tests for Magic Link with secondary storage.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/core/src/types/context.ts Extends InternalAdapter with updateVerificationByIdentifier.
packages/better-auth/src/db/internal-adapter.ts Adds secondary-storage reverse mapping + secondary-only update/delete support; adds updateVerificationByIdentifier.
packages/better-auth/src/plugins/magic-link/index.ts Switches Magic Link attempt tracking/cleanup to identifier-based update/delete.
packages/better-auth/src/plugins/magic-link/magic-link.test.ts Adds regression tests covering Magic Link flows with secondary storage enabled.
Comments suppressed due to low confidence (1)

packages/better-auth/src/db/internal-adapter.ts:1277

  • updateVerificationByIdentifier updates the cached JSON under the key derived from the input identifier. If data.identifier is being updated (some flows update a verification row to a new identifier), the secondary-storage entry should be migrated to the new verification:${newStoredIdentifier} key (and any verification-id:${id} reverse mapping updated) so future lookups by the new identifier work in secondary-only mode.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1226 to +1234
}

if (!secondaryStorage || options.verification?.storeInDatabase) {
const verification = await updateWithHooks<Verification>(
data,
[{ field: "identifier", value: storedIdentifier }],
"verification",
undefined,
);
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the secondary-storage update path, updates that change identifier will leave the cached entry under the old verification:${storedIdentifier} key and keep verification-id:${id} pointing at the old identifier. This makes the verification unreachable via findVerificationValue(newIdentifier) in secondary-only mode (and can also cause later updates/deletes by id to target the wrong key). Consider detecting updateData.identifier changes and, if present, recomputing the new stored identifier, moving the cache entry to the new key, and updating the reverse mapping accordingly (including deleting the old key/mapping).

Copilot uses AI. Check for mistakes.
@vercel vercel bot temporarily deployed to Preview – better-auth-docs March 1, 2026 11:41 Inactive
Move magic link secondary storage tests from the plugin test file to
test/unit/ for better organization and real-world integration testing.
Adds coverage for pre-parsed object storage (e.g., Redis wrappers).
@himself65 himself65 force-pushed the fix/magic-link-secondary-storage branch from 83812ad to 102f6c3 Compare March 1, 2026 11:53
@vercel vercel bot temporarily deployed to Preview – better-auth-docs March 1, 2026 11:53 Inactive
…sed only

Migrate all callers of deleteVerificationValue(id) and
updateVerificationValue(id, data) to use deleteVerificationByIdentifier
and updateVerificationByIdentifier. This ensures all verification
operations work correctly with both secondary storage and database
storage, fixing the root cause of #8228 across all plugins.
@himself65 himself65 changed the title fix(db): support verification CRUD operations with secondary storage fix(db): support verification operations with secondary storage Mar 1, 2026
@himself65 himself65 force-pushed the fix/magic-link-secondary-storage branch from 102f6c3 to 1aafea2 Compare March 1, 2026 12:11
@vercel vercel bot temporarily deployed to Preview – better-auth-docs March 1, 2026 12:11 Inactive
@himself65 himself65 force-pushed the fix/magic-link-secondary-storage branch from 1aafea2 to d574d18 Compare March 1, 2026 12:13
@vercel vercel bot temporarily deployed to Preview – better-auth-docs March 1, 2026 12:13 Inactive
@himself65 himself65 added this pull request to the merge queue Mar 1, 2026
Merged via the queue into canary with commit d341824 Mar 1, 2026
17 checks passed
rae-fcm pushed a commit to FullCodeMedical/better-auth that referenced this pull request Mar 9, 2026
rae-fcm pushed a commit to FullCodeMedical/better-auth that referenced this pull request Mar 9, 2026
rae-fcm pushed a commit to FullCodeMedical/better-auth that referenced this pull request Mar 10, 2026
@better-auth better-auth locked as resolved and limited conversation to collaborators Mar 31, 2026
@bytaesu bytaesu added the locked Locked conversations after being closed for 7 days label Mar 31, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

locked Locked conversations after being closed for 7 days

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Schema generation removes magic link verifications & Magic link sign-in broken since 1.5.0

3 participants