fix(auth): add allowCredentials to login challenge options when username provided

This commit is contained in:
Tyler Gillispie 2026-08-24 15:36:54 -07:00
parent cf42a32800
commit 324ad24d05
2 changed files with 22 additions and 14 deletions

View File

@ -385,11 +385,7 @@ Deno.test("WebAuthn - /api/login/challenge handles username for PRF", async () =
if (query.includes("SELECT id FROM users WHERE username =")) { if (query.includes("SELECT id FROM users WHERE username =")) {
return Promise.resolve([{ id: "mock-user-id" }]); return Promise.resolve([{ id: "mock-user-id" }]);
} }
if ( if (query.includes("FROM passkeys WHERE user_id =")) {
query.includes(
"SELECT credential_id, prf_enabled, prf_salt FROM passkeys WHERE user_id =",
)
) {
return Promise.resolve([{ return Promise.resolve([{
credential_id: "mock-cred", credential_id: "mock-cred",
prf_enabled: true, prf_enabled: true,

View File

@ -658,8 +658,8 @@ app.post("/api/login/challenge", async (c) => {
body = {}; body = {};
} }
const username = body.username; const username = body.username;
let extensions: any = undefined; let extensions: any = undefined;
let allowCredentials: any[] | undefined = undefined;
if (username) { if (username) {
const user = await sqlWrapper const user = await sqlWrapper
@ -668,13 +668,23 @@ app.post("/api/login/challenge", async (c) => {
); );
if (user) { if (user) {
const passkeys = await sqlWrapper const passkeys = await sqlWrapper
.sql`SELECT credential_id, prf_enabled, prf_salt FROM passkeys WHERE user_id = ${user.id} AND prf_enabled = true AND prf_salt IS NOT NULL`; .sql`SELECT credential_id, transports, prf_enabled, prf_salt FROM passkeys WHERE user_id = ${user.id}`;
if (passkeys.length > 0) { if (passkeys.length > 0) {
allowCredentials = passkeys.map((pk: any) => ({
id: pk.credential_id,
type: "public-key",
transports: pk.transports || undefined,
}));
const prfPasskeys = passkeys.filter((pk: any) =>
pk.prf_enabled && pk.prf_salt
);
if (prfPasskeys.length > 0) {
extensions = { extensions = {
["prf" as string]: { evalByCredential: {} }, ["prf" as string]: { evalByCredential: {} },
}; };
for (const pk of passkeys) { for (const pk of prfPasskeys) {
const saltBytes = decodeBase64Url(pk.prf_salt); const saltBytes = decodeBase64Url(pk.prf_salt);
extensions["prf"]["evalByCredential"][pk.credential_id] = { extensions["prf"]["evalByCredential"][pk.credential_id] = {
first: saltBytes, first: saltBytes,
@ -683,11 +693,13 @@ app.post("/api/login/challenge", async (c) => {
} }
} }
} }
}
const options = await generateAuthenticationOptions({ const options = await generateAuthenticationOptions({
rpID, rpID,
userVerification: "preferred", userVerification: "preferred",
timeout: 60000, timeout: 60000,
allowCredentials,
extensions, extensions,
}); });