Conversation
better-auth defaults to an in-process memory store, which on a serverless platform means each cold start begins with an empty counter and instances never see each other's. The built-in limits it ships — 3 sign-in attempts per 10s, 3 reset or verification mails per 60s — were counting almost nothing as a result. Adds the rate_limit table the storage backend reads, which the schema generator emits once storage is set. Also restores the apikey.metadata warning in the generator's own header, so the next regeneration stops dropping it.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
createAuthnever configuredrateLimit, so better-auth used its defaults: enabled in production,storage: "memory".That store is a module-scope
Mapin the app process. On a serverless platform every cold start begins with an empty counter and instances never see each other's, so the limits better-auth ships were counting close to nothing:/sign-in*,/sign-up*,/change-password*,/change-email*/request-password-reset,/send-verification-email,/forget-password*Those windows are fine — the storage behind them was the problem. This switches it to
storage: "database", which counts in Postgres with an atomic guarded update (incrementOne, implemented by the drizzle adapter).Changes
rateLimit: { storage: "database" }in the shared auth factory. No custom rules — better-auth's own windows are what we want, they just need somewhere durable to count.rate_limittable, emitted by the better-auth schema generator (it only adds the table oncestorageis set) and its migration,0021_rate_limit.sql.apikey.metadatawarning ingenerate-auth-schema.sh's header. The committedschema-auth.tshad it but the script did not, so regenerating dropped it — as it did here before I put it back.enabledis left at better-auth's default of "production only", so local dev is unaffected.Deploying
Needs the migration applied before the app starts. The self-hosted compose already orders this correctly —
db-migrateis an init container that web and workerdepends_on: service_completed_successfully. Cloud needs the migration in the deploy step ahead of the rollout; on an instance whererate_limitis missing, better-auth's rate limiter has no table to count in.Verification
drizzle-kit generateproduced only the new table — no drift in the rest of the snapshot. Lint andtsc --noEmitpass onpackages/lib. Not exercised against a live database; I did not run migrations.Open workspace in Conductor