···322322 return Response.json({ error: "Account is suspended" }, { status: 403 });
323323 }
324324325325- // Get user's credentials
325325+ // Get user's credentials (just to verify they exist)
326326 const credentials = db
327327 .query("SELECT credential_id FROM credentials WHERE user_id = ?")
328328 .all(user.id) as { credential_id: Buffer }[];
···335335 }
336336337337 // Generate authentication options
338338- // Include allowCredentials to filter to only this user's passkeys
338338+ // Use discoverable credentials (no allowCredentials) for better UX
339339 const options: PublicKeyCredentialRequestOptionsJSON =
340340 await generateAuthenticationOptions({
341341 rpID: process.env.RP_ID!,
342342 userVerification: "required",
343343- allowCredentials: credentials.map(c => ({
344344- id: c.credential_id.toString('base64url'),
345345- type: 'public-key' as const,
346346- transports: ['hybrid', 'internal', 'usb', 'ble', 'nfc'] as AuthenticatorTransportFuture[],
347347- })),
348343 });
349344350345 // Store challenge
···375370 );
376371 }
377372378378- // Look up credential by ID
379379- // Current database has credential_id stored as Buffer containing ASCII text of base64url string
380380- // So we need to compare the string value, not decode it
381381- const credentialIdString = response.id; // This is the base64url string like "rHvdOyMkR-6nxGBcDmtV4g"
373373+ // Look up credential by ID to discover the username
374374+ const credentialIdString = response.id;
382375383376 const credentialWithUser = db
384377 .query(
···403396 );
404397 }
405398406406- // Verify the username matches (if provided)
407407- if (username && credentialWithUser.username !== username) {
399399+ // Verify the username matches
400400+ if (credentialWithUser.username !== username) {
408401 return Response.json(
409402 { error: "Credential does not belong to this user" },
410403 { status: 403 },
···419412 const user = { id: credentialWithUser.user_id };
420413421414 // Verify challenge exists and is valid
422422- // Use the discovered username from the credential
423415 const challenge = db
424416 .query(
425417 "SELECT challenge, expires_at FROM challenges WHERE username = ? AND type = 'authentication' ORDER BY created_at DESC LIMIT 1",
426418 )
427427- .get(credentialWithUser.username) as
419419+ .get(username) as
428420 | { challenge: string; expires_at: number }
429421 | undefined;
430422