my own indieAuth provider! indiko.dunkirk.sh/docs
indieauth oauth2-server
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add autofill

+7 -15
+7 -15
src/routes/auth.ts
··· 322 322 return Response.json({ error: "Account is suspended" }, { status: 403 }); 323 323 } 324 324 325 - // Get user's credentials 325 + // Get user's credentials (just to verify they exist) 326 326 const credentials = db 327 327 .query("SELECT credential_id FROM credentials WHERE user_id = ?") 328 328 .all(user.id) as { credential_id: Buffer }[]; ··· 335 335 } 336 336 337 337 // Generate authentication options 338 - // Include allowCredentials to filter to only this user's passkeys 338 + // Use discoverable credentials (no allowCredentials) for better UX 339 339 const options: PublicKeyCredentialRequestOptionsJSON = 340 340 await generateAuthenticationOptions({ 341 341 rpID: process.env.RP_ID!, 342 342 userVerification: "required", 343 - allowCredentials: credentials.map(c => ({ 344 - id: c.credential_id.toString('base64url'), 345 - type: 'public-key' as const, 346 - transports: ['hybrid', 'internal', 'usb', 'ble', 'nfc'] as AuthenticatorTransportFuture[], 347 - })), 348 343 }); 349 344 350 345 // Store challenge ··· 375 370 ); 376 371 } 377 372 378 - // Look up credential by ID 379 - // Current database has credential_id stored as Buffer containing ASCII text of base64url string 380 - // So we need to compare the string value, not decode it 381 - const credentialIdString = response.id; // This is the base64url string like "rHvdOyMkR-6nxGBcDmtV4g" 373 + // Look up credential by ID to discover the username 374 + const credentialIdString = response.id; 382 375 383 376 const credentialWithUser = db 384 377 .query( ··· 403 396 ); 404 397 } 405 398 406 - // Verify the username matches (if provided) 407 - if (username && credentialWithUser.username !== username) { 399 + // Verify the username matches 400 + if (credentialWithUser.username !== username) { 408 401 return Response.json( 409 402 { error: "Credential does not belong to this user" }, 410 403 { status: 403 }, ··· 419 412 const user = { id: credentialWithUser.user_id }; 420 413 421 414 // Verify challenge exists and is valid 422 - // Use the discovered username from the credential 423 415 const challenge = db 424 416 .query( 425 417 "SELECT challenge, expires_at FROM challenges WHERE username = ? AND type = 'authentication' ORDER BY created_at DESC LIMIT 1", 426 418 ) 427 - .get(credentialWithUser.username) as 419 + .get(username) as 428 420 | { challenge: string; expires_at: number } 429 421 | undefined; 430 422