[PR #2632] [CLOSED] Fix: Set pending 2FA cookie during setup to prevent INVALID_TWO_FACTOR_COOKIE error (#2631) #21313

Closed
opened 2026-04-15 20:16:31 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/2632
Author: @obendev
Created: 5/12/2025
Status: Closed

Base: mainHead: fix/2631-2fa-enable-cookie


📝 Commits (1)

  • f80aa41 fix(two-factor): Set pending cookie on 2FA enable (#2631)

📊 Changes

1 file changed (+59 additions, -17 deletions)

View changed files

📝 packages/better-auth/src/plugins/two-factor/index.ts (+59 -17)

📄 Description

Closes #2631

Problem:

When setting up 2FA (TOTP) using the twoFactor plugin with the default skipVerificationOnEnable: false setting, submitting the TOTP code via /two-factor/verify-totp incorrectly resulted in an INVALID_TWO_FACTOR_COOKIE error. This occurred even when testing with an intentionally incorrect TOTP code, where an INVALID_CODE error was expected.

Root Cause:

The analysis traced this back to the /two-factor/enable endpoint handler in packages/better-auth/src/plugins/two-factor/index.ts. When skipVerificationOnEnable is false, this handler successfully generated the totpURI but failed to set the necessary TWO_FACTOR_COOKIE_NAME. This cookie is required by the verifyTwoFactor helper (used by /two-factor/verify-totp) to link the verification attempt back to the correct user and pending state. Without the cookie, the verification flow failed before the submitted TOTP code could actually be validated.

Solution:

This PR modifies the enableTwoFactor handler to address this gap. When skipVerificationOnEnable is false, the handler now mirrors the logic used in the sign-in after hook for establishing a pending 2FA state:

  1. It creates a unique verification identifier.
  2. It stores this identifier in the verification database table, linked to the userId and including an expiry time (consistent with the sign-in hook: options?.otpOptions?.period || 60 * 5).
  3. It sets the signed TWO_FACTOR_COOKIE_NAME on the client response, containing this identifier.

Outcome:

With this change, the /two-factor/verify-totp endpoint can now correctly find the pending verification context using the cookie. It can then proceed to validate the submitted TOTP code against the stored secret, returning INVALID_CODE for incorrect codes or successfully enabling 2FA for correct codes.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/2632 **Author:** [@obendev](https://github.com/obendev) **Created:** 5/12/2025 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/2631-2fa-enable-cookie` --- ### 📝 Commits (1) - [`f80aa41`](https://github.com/better-auth/better-auth/commit/f80aa41449ed0aa016c6e426c4f608cdbde55dc6) fix(two-factor): Set pending cookie on 2FA enable (#2631) ### 📊 Changes **1 file changed** (+59 additions, -17 deletions) <details> <summary>View changed files</summary> 📝 `packages/better-auth/src/plugins/two-factor/index.ts` (+59 -17) </details> ### 📄 Description Closes #2631 **Problem:** When setting up 2FA (TOTP) using the `twoFactor` plugin with the default `skipVerificationOnEnable: false` setting, submitting the TOTP code via `/two-factor/verify-totp` incorrectly resulted in an `INVALID_TWO_FACTOR_COOKIE` error. This occurred even when testing with an intentionally incorrect TOTP code, where an `INVALID_CODE` error was expected. **Root Cause:** The analysis traced this back to the `/two-factor/enable` endpoint handler in `packages/better-auth/src/plugins/two-factor/index.ts`. When `skipVerificationOnEnable` is `false`, this handler successfully generated the `totpURI` but failed to set the necessary `TWO_FACTOR_COOKIE_NAME`. This cookie is required by the `verifyTwoFactor` helper (used by `/two-factor/verify-totp`) to link the verification attempt back to the correct user and pending state. Without the cookie, the verification flow failed before the submitted TOTP code could actually be validated. **Solution:** This PR modifies the `enableTwoFactor` handler to address this gap. When `skipVerificationOnEnable` is `false`, the handler now mirrors the logic used in the sign-in `after` hook for establishing a pending 2FA state: 1. It creates a unique verification `identifier`. 2. It stores this identifier in the `verification` database table, linked to the `userId` and including an expiry time (consistent with the sign-in hook: `options?.otpOptions?.period || 60 * 5`). 3. It sets the signed `TWO_FACTOR_COOKIE_NAME` on the client response, containing this `identifier`. **Outcome:** With this change, the `/two-factor/verify-totp` endpoint can now correctly find the pending verification context using the cookie. It can then proceed to validate the submitted TOTP code against the stored secret, returning `INVALID_CODE` for incorrect codes or successfully enabling 2FA for correct codes. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-15 20:16:31 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#21313