webauthnlisted
Install: claude install-skill claude-dev-suite/claude-dev-suite
# WebAuthn / Passkeys
## Server Setup (SimpleWebAuthn)
```typescript
import {
generateRegistrationOptions,
verifyRegistrationResponse,
generateAuthenticationOptions,
verifyAuthenticationResponse,
} from '@simplewebauthn/server';
const rpName = 'My App';
const rpID = 'myapp.com';
const origin = 'https://myapp.com';
```
## Registration Flow
### Server: Generate Options
```typescript
app.post('/api/auth/register/options', auth, async (req, res) => {
const user = req.user;
const existingCredentials = await db.credential.findMany({
where: { userId: user.id },
});
const options = await generateRegistrationOptions({
rpName,
rpID,
userName: user.email,
userDisplayName: user.name,
excludeCredentials: existingCredentials.map((c) => ({
id: c.credentialId,
transports: c.transports,
})),
authenticatorSelection: {
residentKey: 'preferred',
userVerification: 'preferred',
},
});
// Store challenge for verification
await db.challenge.upsert({
where: { userId: user.id },
create: { userId: user.id, challenge: options.challenge },
update: { challenge: options.challenge },
});
res.json(options);
});
```
### Server: Verify Registration
```typescript
app.post('/api/auth/register/verify', auth, async (req, res) => {
const user = req.user;
const { challenge } = await db.challenge.findUnique({ where: { userId: user.id } });
const verification = await verifyRegistrationResponse({
resp