Added throttle for passphrase login

This commit is contained in:
Karl Ludwig Weise
2026-05-05 15:27:40 +02:00
parent f833dbf500
commit b283dbb670
2 changed files with 31 additions and 1 deletions
@@ -12,7 +12,7 @@ import { challengeThrottle } from "$lib/server/db/central-schema";
import { eq, lt, sql } from "drizzle-orm";
import { logger } from "$lib/logger";
export type ThrottleType = "pin" | "passkey";
export type ThrottleType = "pin" | "passkey" | "passphrase";
interface ThrottleResult {
allowed: boolean;
+30
View File
@@ -137,6 +137,32 @@ export const POST: RequestHandler = async ({ request, cookies, getClientAddress,
authMethod: body.passphrase ? "passphrase" : "webauthn",
});
const throttleResult = await challengeThrottleService.checkThrottle(
body.email,
body.passphrase ? "passphrase" : "passkey",
);
if (!throttleResult.allowed) {
logger.warn("Login throttled", {
email: body.email,
retryAfterMs: throttleResult.retryAfterMs,
failedAttempts: throttleResult.failedAttempts,
});
return json(
{
error: "Too many failed attempts. Please try again later.",
retryAfterMs: throttleResult.retryAfterMs,
},
{
status: 429,
headers: {
"Retry-After": Math.ceil(throttleResult.retryAfterMs / 1000).toString(),
},
},
);
}
// Validate that either passphrase or credential is provided
if (!body.passphrase && !body.credential) {
return json(
@@ -222,9 +248,13 @@ export const POST: RequestHandler = async ({ request, cookies, getClientAddress,
const isPassphraseValid = await verifyPassphrase(user.passphraseHash, body.passphrase);
if (!isPassphraseValid) {
await challengeThrottleService.recordFailedAttempt(body.email, "passphrase");
return json({ error: "Invalid passphrase" }, { status: 401 });
}
// Clear throttle on successful authentication
await challengeThrottleService.clearThrottle(body.email, "passphrase");
logger.debug("Passphrase authentication successful", { userId: user.id });
}