Back to Blog

How to Build a Secure Forgot Password Flow with OTP in Better Auth

Royan Gagas
January 3, 2026
Share
react
tips
development
How to Build a Secure Forgot Password Flow with OTP in Better Auth

In our previous guide, we set up Better Auth with Nodemailer to handle email verification and invites. Today, we are tackling a critical feature for any production app: The "Forgot Password" flow.

While Magic Links (links that log you in or reset your password immediately) are popular, they force the user to leave your app, open their email, and click a link that opens a new tab.

Sometimes, you want to keep the user right where they are. In this guide, we will build an OTP (One-Time Password) reset flow. The user enters their email, receives a 6-digit code, and resets their password without ever closing your tab.

The Backend Config

Good news: If you followed the previous guide, your backend is already ready.

The emailOTP plugin we installed previously handles the forget-password type automatically. When we call the forgot password function from the client, Better Auth will trigger the sendVerificationOTP hook we defined in auth.ts with the type set to "forget-password".

Just ensure your email.ts template handles the subject line dynamically (or generic enough) for password resets.

The Client-Side Implementation

We need to handle two distinct stages in our UI:

1.Request Stage: User enters email -> System sends OTP.
2.Reset Stage: User enters OTP + New Password -> System updates credentials.

1. The Logic Hooks

Instead of dumping 200 lines of UI code, let's look at the core functions using authClient.

2. The UI Implementation

Here is how we compose the UI. I've simplified the styling to focus on the structure, but you can keep your Tailwind gradients for that premium feel.

The Request Form (Stage 1):

The Reset Form (Stage 2):

Magic Link vs. OTP: Which one should you choose?

I chose OTP for implementation, but Better Auth support both. Here is a quick breakdown to help you decide which fits your app better.

The OTP Approach (This Guide)

Pros:

Seamless Context: The user never leaves your application tab. This reduces "drop-off" rates.
Mobile Friendly: Great for mobile apps where handling deep links (Universal Links) can be buggy or complex to set up.
Perceived Security: Users are accustomed to 2FA codes; it feels secure to enter a code.

Cons:

Friction: The user has to manually copy and paste (or type) a code.
Typos: Users might mistype the code or the password, requiring error handling.

The Magic Link Approach

Pros:

Zero Friction: One click and they are done.
Simple: No need for the user to understand what a "code" is.

Cons:

Context Switching: Forces the user to open a new browser window/tab.
Email Scanners: aggresive enterprise email scanners sometimes "click" links to check for malware, which can accidentally invalidate one-time tokens before the user sees them.

Conclusion

By using the emailOTP plugin in Better Auth, we've created a password reset flow that keeps users engaged within our application. It's a small UX detail, but keeping users inside your app ecosystem always leads to higher conversion and retention.