mirror of
https://github.com/better-auth/better-auth.git
synced 2026-07-20 00:33:45 -05:00
docs(two-factor): document newSession is null during 2FA challenge (#9957)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"better-auth": patch
|
||||
---
|
||||
|
||||
Document that `ctx.context.newSession` is `null` while a two-factor challenge is in flight. When a 2FA-enabled user signs in through a credential endpoint, the pending session is discarded and `newSession` is reset to `null` (no authenticated session exists until the second factor is verified). Server-side `after` hooks reading `ctx.context.newSession` must null-check it before accessing `newSession.user`. This clarifies the behavior change introduced in #9639.
|
||||
@@ -120,6 +120,10 @@ By default, 2FA sign-in enforcement applies to the credential-based sign-in endp
|
||||
|
||||
If your app needs to require 2FA for those sign-in methods, add custom hook handling for those endpoints and redirect users into your 2FA verification flow before treating the sign-in as complete.
|
||||
|
||||
<Callout type="warn">
|
||||
When a 2FA-enabled user signs in via a credential endpoint, the plugin issues a 2FA challenge instead of completing the sign-in. As part of this, the pending session is discarded and `ctx.context.newSession` is reset to `null` — there is no authenticated session until the user verifies the second factor. Server-side hooks (e.g. `after` hooks on the sign-in endpoints) that read `ctx.context.newSession` must null-check it before accessing `newSession.user`, otherwise they will throw while a 2FA challenge is in flight.
|
||||
</Callout>
|
||||
|
||||
You can handle this in the `onSuccess` callback or by providing a `onTwoFactorRedirect` callback in the plugin config.
|
||||
|
||||
```tsx
|
||||
|
||||
@@ -469,7 +469,15 @@ export const twoFactor = <O extends TwoFactorOptions>(options?: O) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the session cookie. It's set by the sign in credential
|
||||
* Remove the session cookie set by the credential sign-in.
|
||||
*
|
||||
* The credential handler already created a session and set
|
||||
* `ctx.context.newSession`. Since 2FA is still pending, that
|
||||
* session is deleted here and `newSession` is reset to `null`
|
||||
* so downstream hooks don't observe a session that no longer
|
||||
* exists. Hooks that read `ctx.context.newSession` after a
|
||||
* sign-in must therefore null-check it: it is `null` while a
|
||||
* 2FA challenge is in flight (no authenticated session yet).
|
||||
*/
|
||||
deleteSessionCookie(ctx, true);
|
||||
await ctx.context.internalAdapter.deleteSession(data.session.token);
|
||||
|
||||
Reference in New Issue
Block a user