Introduction
Passwords are outdated — implement passkey authentication with WebAuthn (FIDO2). Let Claude Code design TouchID/FaceID/Windows Hello authentication.
CLAUDE.md Rules
## WebAuthn Design Rules
- Challenge: random 32 bytes per request
- rpID: fixed production domain (anti-phishing)
- userVerification: required (force biometrics)
- signCount validation: detect replay attacks
- Clone detection: invalidate if signCount regresses
Generated Implementation
// src/auth/webauthn.ts
import {
generateRegistrationOptions,
verifyRegistrationResponse,
generateAuthenticationOptions,
verifyAuthenticationResponse,
} from '@simplewebauthn/server';
// Registration: prevent session fixation
export async function startRegistration(userId: string) {
const options = await generateRegistrationOptions({
rpName: RP_NAME,
rpID: RP_ID,
userID: Buffer.from(userId),
authenticatorSelection: {
residentKey: 'preferred',
userVerification: 'required',
},
});
await redis.set(`webauthn:reg:challenge:${userId}`, options.challenge, { EX: 60 });
return options;
}
// Authentication with clone detection
export async function finishAuthentication(sessionId: string, credential: any) {
const passkey = await prisma.passkey.findFirst({
where: { credentialId: credential.id },
});
const verification = await verifyAuthenticationResponse({
response: credential,
expectedChallenge,
expectedOrigin: ORIGIN,
expectedRPID: RP_ID,
authenticator: {
credentialPublicKey: Buffer.from(passkey.publicKey, 'base64'),
counter: passkey.counter,
},
requireUserVerification: true,
});
// Clone detection: signCount regression
if (verification.authenticationInfo.newCounter < passkey.counter) {
await prisma.passkey.update({
where: { id: passkey.id },
data: { revokedAt: new Date(), revokedReason: 'counter_regression' },
});
throw new SecurityError('Passkey may be cloned');
}
await prisma.passkey.update({
where: { id: passkey.id },
data: { counter: verification.authenticationInfo.newCounter },
});
return { userId: passkey.userId };
}
Summary
- Challenge: random 32 bytes stored in Redis for 60s
- signCount regression detection for clone protection
- discoverable credentials: no email input required
- Multiple device management with device names
Review with **Security Pack (¥1,480)* /security-check at prompt-works.jp*
myouga (@myougatheaxo) — Axolotl VTuber.
Top comments (0)