Rate Limiting Does Not Work

I'm trying to test rate limiting on dev, but unfortunately it doesn't limit anything. This is my config:
rateLimit: {
enabled: true,
window: 60,
max: 1,
storage: "memory",
},
rateLimit: {
enabled: true,
window: 60,
max: 1,
storage: "memory",
},
This is how I try to test the rate limiting:
<button class="btn"
on:click={async () => {
const response = await authClient.signIn.email({
email: "xxx",
password: "xxx"
});
if (response?.data && !response.error) {
goto("/dashboard")
}
}}
>Login
</button>
<button class="btn"
on:click={async () => {
const response = await authClient.signIn.email({
email: "xxx",
password: "xxx"
});
if (response?.data && !response.error) {
goto("/dashboard")
}
}}
>Login
</button>
Due to the config, I'd expect that I can only log in once per minute. But unfortunately, I'm not getting rate limited. Any ideas?
27 Replies
sebastian
sebastian3mo ago
Have you tried with redis as a storage?
battlesheep123
battlesheep123OP3mo ago
No, I thought "memory" is a valid option.
sebastian
sebastian3mo ago
I mean you can use it i think, but its not a valid approach for production apps In addition to the default settings, Better Auth provides custom rules for specific paths. For example: /sign-in/email: Is limited to 3 requests within 10 seconds. In addition, plugins also define custom rules for specific paths. For example, twoFactor plugin has custom rules: /two-factor/verify: Is limited to 3 requests within 10 seconds. These custom rules ensure that sensitive operations are protected with stricter limits. have you read the docs? maybe you have to change the custom path i mean
export const auth = betterAuth({
//...other options
rateLimit: {
window: 60, // time window in seconds
max: 100, // max requests in the window
customRules: {
"/sign-in/email": {
window: 10,
max: 3,
},
"/two-factor/*": async (request)=> {
// custom function to return rate limit window and max
return {
window: 10,
max: 3,
}
}
},
},
})
export const auth = betterAuth({
//...other options
rateLimit: {
window: 60, // time window in seconds
max: 100, // max requests in the window
customRules: {
"/sign-in/email": {
window: 10,
max: 3,
},
"/two-factor/*": async (request)=> {
// custom function to return rate limit window and max
return {
window: 10,
max: 3,
}
}
},
},
})
battlesheep123
battlesheep123OP3mo ago
yes, I checked the docs and also tried with the custom rules. also did not work.
sebastian
sebastian3mo ago
try adding the window and max to the /sign-in/email then try using redis as your storage if these not work
battlesheep123
battlesheep123OP3mo ago
I changed to storage: "database", but it still doesn't work.
kingitaj
kingitaj3mo ago
Same here! So far, I haven't managed to get it to work locally. I've enabled it in the config, but I've only been making API calls from the API explorer, so idk if those requests don't get rate-limited. I'll try with the actual client apps soon.
Ping
Ping3mo ago
Hey guys, just tested on my end and things are not working either :/ It's odd because I'm pretty certain we have unit-tests on this, I'll dig further and let yall know if I find anything. Yeah, auth.api doesn't get rate-limited. Okay just talked to Bekacru, and it's most likely because there may not be an ip address in dev. Please everyone check that your session table has ip_address field not empty, if it's empty then rate-limits can't be captured
battlesheep123
battlesheep123OP3mo ago
That's exactly the problem. The "rateLimit" table was empty the whole time. I just re-tested using ngrok and it works. Any idea how we can work around that in dev?
Ping
Ping3mo ago
I'm not too sure. I'll ask Bekacru and if he has a solution then I'll get back to you.
battlesheep123
battlesheep123OP3mo ago
awesome, thanks!!
Ping
Ping3mo ago
I don't think theres a way right now sadly
battlesheep123
battlesheep123OP3mo ago
Thank you anyways for double-checking. For others having the same issue: try using ngrok or Localcan with public URLs.
Budi
Budi3mo ago
@Ping Why do you only capture rate limits when ip_address is available on the session? Does this mean that hits to /api/auth* without a session (or session.ip_address) are not rate limited? Or are those not persisted to the database? Are those stored in memory? Or not rate limited at all? Effectively I'm asking how this would protect us from brute force attacks on say an email+password login field.
rocketkittens
rocketkittens3mo ago
the ip_address is captured from headers, right? which one?
fynn
fynn3mo ago
@Ping May I ask, if there's an update on this?
Ping
Ping3mo ago
We currently rely on the ip_address that would theoretically be available on the session. However, if no proxy or middleware is configured to add IP headers, requests won't be rate-limited. In the future, we plan to introduce more advanced strategies to handle cases where the IP is unavailable - such as falling back to user data or implementing fingerprinting - but these features are still under consideration.
Budi
Budi3mo ago
I see so to be safe, I would need to add middleware that adds IP headers for non-authenticated users trying to break in?
Ping
Ping3mo ago
Yeah. For example lots of people use Cloudflare.
fynn
fynn3mo ago
how would I then provide these headers to the rate limiter? e.g. in the forget route, currently our users could easily send thousands of emails and a session is not available, as they are not logged in
rocketkittens
rocketkittens3mo ago
which header? X-Forwarded-For?
fynn
fynn3mo ago
even with that, e.g. the forget route can spammed
Budi
Budi3mo ago
Sounds like the best approach would be to add another rate limiter on that path, until the BA rate limiter is improved. This appears to be quite an enumeration risk vector. So you would set ipAddressHeaders: ["x-client-ip", "x-forwarded-for"] in the advanced settings, and then need to ensure these are set via middleware for non-authenticated interactions with any /auth/api*path?
fynn
fynn3mo ago
yes, in any case. this should be adressed
dun
dun5d ago
hi @Ping , so this rate limit is work if user already loggedin / have a session?
Ping
Ping5d ago
It's based on ip

Did you find this page helpful?