Harden passkey management

This commit is contained in:
Karl Ludwig Weise
2026-08-20 09:01:52 +02:00
parent 28805d2421
commit cecb24dd78
4 changed files with 19 additions and 0 deletions
+1
View File
@@ -798,6 +798,7 @@
"action": "Hinzufügen",
"success": "Passkey hinzugefügt",
"error": "Passkey konnte nicht hinzugefügt werden",
"errorDeleteSuccess": "Teilweise hinzugefügter Passkey gelöscht",
"maxReached": {
"title": "Maximum erreicht",
"description": "Du hast bereits die maximale Anzahl von Passkeys für Deinen Account erreicht"
+1
View File
@@ -806,6 +806,7 @@
"action": "Add Passkey",
"success": "Passkey added",
"error": "Passkey could not be added",
"errorDeleteSuccess": "Partially added Passkey deleted",
"maxReached": {
"title": "Maximum reached",
"description": "You've reached the maximum amount of Passkeys for this account"
@@ -167,6 +167,17 @@
} catch (error) {
console.error("Unable to add passkey", error);
toast.error(m["account.passkeys.add.error"]());
// Try to delete the partially added passkey if it was created
await fetch(`/api/auth/passkeys/${$formData.id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ tenantId }),
credentials: "same-origin",
});
toast.info(m["account.passkeys.add.errorDeleteSuccess"]());
} finally {
isSubmitting = false;
}
+6
View File
@@ -229,10 +229,12 @@ export const POST: RequestHandler = async ({ request, cookies, url }) => {
// Try to get user by email - but don't fail if not found
let user = null;
let isRegistration = false;
let passkeysLength = 0;
try {
user = await UserService.getUserByEmail(requestEmail);
const passkeys = await UserService.getUserPasskeys(user.id);
passkeysLength = passkeys.length;
if (passkeys.length === 0) {
isRegistration = true; // User exists but has no passphrase - must register
}
@@ -279,6 +281,10 @@ export const POST: RequestHandler = async ({ request, cookies, url }) => {
path: "/",
maxAge: 60 * 5, // 5 minutes
});
} else {
if (passkeysLength >= 3) {
throw new BackendError("Maximum number of passkeys reached", 400);
}
}
let allowCredentials: Array<{