OTP immediately expires after creating
Hi Better Auth team,
I’m running into a persistent issue with OTPs in my project. Whenever a user signs up or requests an OTP:
I am using password & email plugin to sign-up user, then we use that email to send a verification email. We also have the Email OTP plugin configured. AuthClient.signUp.email(...)then authClient.emailOtp.sendVerificationOtp(...). We use authClient.emailOtp.verifyEmail(...) to verify the email.
The OTP hash stored looks like this:
$argon2id$v=19$m=65536,t=2,p=1$CeahSRdcP4OnzlR70Mii3NPsdGDSVB8jyruRebGMm6o$h61+yDhggb5cqjtFm9zxbnFyMwzlVmBuxxV7PyLoI3c:0
(this is the Argon2id hash of the OTP 792635)
Server timezone is UTC, database timestamps are UTC.
The problem persists even if I restart the server or try multiple OTPs.
I’m not sure if the issue is with OTP generation, hashing, timing, or the verification flow.
I’m trying to understand:
Why would the the OTP immediately considered expired? We are not using a custom hasher.
I am using postgresql instance running locally, tanstack start, bun, drizzle as orm. I added with Timezone to all the Timezone settings in the auth schema. I thought maybe tz issue but it doesn't resolve.
Any suggestions for debugging or a safe workaround? I might be doing something wrong, so feel free to guide me or ask for any extra context.
Thanks in advance!
I’m running into a persistent issue with OTPs in my project. Whenever a user signs up or requests an OTP:
I am using password & email plugin to sign-up user, then we use that email to send a verification email. We also have the Email OTP plugin configured. AuthClient.signUp.email(...)then authClient.emailOtp.sendVerificationOtp(...). We use authClient.emailOtp.verifyEmail(...) to verify the email.
- A new user is created and the Stripe customer is successfully generated.
- An email containing the OTP is sent to the user.
- As soon as the user tries to verify the OTP, even immediately after receiving it the system responds with “OTP expired.”
The OTP hash stored looks like this:
$argon2id$v=19$m=65536,t=2,p=1$CeahSRdcP4OnzlR70Mii3NPsdGDSVB8jyruRebGMm6o$h61+yDhggb5cqjtFm9zxbnFyMwzlVmBuxxV7PyLoI3c:0
(this is the Argon2id hash of the OTP 792635)
Server timezone is UTC, database timestamps are UTC.
The problem persists even if I restart the server or try multiple OTPs.
I’m not sure if the issue is with OTP generation, hashing, timing, or the verification flow.
I’m trying to understand:
Why would the the OTP immediately considered expired? We are not using a custom hasher.
I am using postgresql instance running locally, tanstack start, bun, drizzle as orm. I added with Timezone to all the Timezone settings in the auth schema. I thought maybe tz issue but it doesn't resolve.
Any suggestions for debugging or a safe workaround? I might be doing something wrong, so feel free to guide me or ask for any extra context.
Thanks in advance!