Magic Link Expiry
Hi there.
When it comes to the expiry of a magic link we noticed that it is set 2h behind. Now we have our DB hosted in the UK (MongoDB) and work in. South Africa.
Are the expiry dates of these tokens based on the DB time or server time? Essentially when working locally we have a our server obviously booted on a SA timezone. So just trying to understand where this behavior comes in?
Thanks
5 Replies
hmm ... ig the expiration will be based on server time (which is gonna be UTC) for most cases and South Africa is UTC + 2:00. thats why there is diff on that
So we saying that if you boot up server locally is it hard coded to UTC?
Expiry is based on UTC both when the token is generated and when it's validated. It doesn’t depend on your server's local timezone or your database’s regional hosting. So regardless of whether you're running your server locally in South Africa or deploying it to production with a DB hosted in the UK, the expiry logic always uses UTC internally. If you’re seeing a 2-hour offset, it’s likely due to how timestamps are being displayed (eg. being shown in local time rather than UTC) rather than how expiry is calculated.
Hmmm the behavior that we see though is that they are not able to login due to the token being 'expired". Is there a way this can be debugged or shown so we can get a better idea of the validation side of things? Or are you 100% convinced that this would not be the issue? We extended the tokens expiry to 6h and it resolved the issue. So interested to know what could be the cause.
I'm also running into this (noticed it with member createdAt, but I think it applies to all entities), and looking through the source code, I'm starting to suspect that the error is with the drizzle adapter (postgres).
This is what it looks like for me running everything locally
* I join an organization at
2025-04-23 10:59:00
in my timezone (UTC+2)
* better-auth generates createdAt with new Date()
and stores it in the DB. Looking in the db table it says 2025-04-23 08:59:00
, which is UTC time.
* Turning on debugLogs in the drizzleAdapter, I'm seeing membership createdAt: 2025-04-23T10:59:00.000Z
, which indicates the timezone info is lost.
So it is clearly not a display thing in the UI. The timezone info is lost when reading from the DB.
Hope this can help debugging the issue on the better-auth end. Maybe all timestamp fields need to have withTimezone: true
in their respective drizzle schemas? https://orm.drizzle.team/docs/column-types/pg#timestampDrizzle ORM - PostgreSQL column types
Drizzle ORM is a lightweight and performant TypeScript ORM with developer experience in mind.