fix: apply rate limits before plugin requests (#10191)

Co-authored-by: Maxwell <145994855+ping-maxwell@users.noreply.github.com>
This commit is contained in:
Taesu
2026-06-24 11:51:11 +00:00
committed by GitHub
co-authored by Maxwell
parent 570267cd5e
commit b046f9ec11
3 changed files with 61 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"better-auth": patch
---
Rate limit client requests before plugin request handlers run.
+6 -5
View File
@@ -301,6 +301,12 @@ export const router = <Option extends BetterAuthOptions>(
}
let currentRequest = req;
const rateLimitResponse = await onRequestRateLimit(currentRequest, ctx);
if (rateLimitResponse) {
return rateLimitResponse;
}
for (const plugin of ctx.options.plugins || []) {
if (plugin.onRequest) {
const response = await withSpan(
@@ -320,11 +326,6 @@ export const router = <Option extends BetterAuthOptions>(
}
}
const rateLimitResponse = await onRequestRateLimit(currentRequest, ctx);
if (rateLimitResponse) {
return rateLimitResponse;
}
return currentRequest;
},
async onResponse(res, req) {
@@ -91,6 +91,56 @@ describe("captcha", async () => {
expect(res.error?.status).toBe(400);
});
it("should apply rate limits before verifying captcha tokens", async () => {
mockBetterFetch.mockClear();
mockBetterFetch.mockResolvedValue({
data: {
success: false,
"error-codes": ["invalid-input-response"],
},
});
const { client, testUser } = await getTestInstance({
rateLimit: {
enabled: true,
customRules: {
"/sign-in/email": {
window: 10,
max: 1,
},
},
},
plugins: [
captcha({
provider: "cloudflare-turnstile",
secretKey: "xx-secret-key",
}),
],
});
const first = await client.signIn.email({
email: testUser.email,
password: testUser.password,
fetchOptions: {
headers: {
"x-captcha-response": "invalid-captcha-token",
},
},
});
const second = await client.signIn.email({
email: testUser.email,
password: testUser.password,
fetchOptions: {
headers: {
"x-captcha-response": "invalid-captcha-token",
},
},
});
expect(first.error?.status).toBe(403);
expect(second.error?.status).toBe(429);
expect(mockBetterFetch).toHaveBeenCalledTimes(1);
});
it("Should return 500 if an unexpected error occurs", async () => {
const { client } = await getTestInstance({
plugins: [