fix(passkey): derive WebAuthn user.id deterministically to stop duplicates
Retries of /api/register/start previously generated a fresh random user.id each time, so the authenticator (iCloud Keychain, Windows Hello, 1Password, etc.) stored a brand-new passkey per attempt. Users who hit the failing registration flow ended up with three or four orphan passkeys in their password manager for every successful one. WebAuthn spec: a create() ceremony with the same (rpId, user.id) overwrites the existing passkey. Deriving user.id as SHA-256(salt + username) means repeated start calls for the same username produce the same user.id and the authenticator overwrites in place. Salt chain: USER_ID_SALT → JWT_SECRET → fallback constant. No new env var needed in prod — JWT_SECRET is already set.
This commit is contained in:
parent
43d68fd521
commit
1471d1d578
|
|
@ -579,8 +579,17 @@ app.post('/api/register/start', async (c) => {
|
|||
// Generate challenge
|
||||
const challenge = Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64url');
|
||||
|
||||
// Generate user ID
|
||||
const userId = Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64url');
|
||||
// Derive userId deterministically from username so repeated /start calls for
|
||||
// the same username produce the same WebAuthn user.id. Per WebAuthn spec, a
|
||||
// repeated create() ceremony with the same (rpId, user.id) overwrites the
|
||||
// existing passkey instead of creating a new one — stops failed retries from
|
||||
// leaving orphan passkeys behind in the user's password manager.
|
||||
const userIdSalt = process.env.USER_ID_SALT || process.env.JWT_SECRET || 'encryptid-user-id';
|
||||
const userIdBuf = await crypto.subtle.digest(
|
||||
'SHA-256',
|
||||
new TextEncoder().encode(`${userIdSalt}:${username.toLowerCase()}`),
|
||||
);
|
||||
const userId = Buffer.from(userIdBuf).toString('base64url');
|
||||
|
||||
// Store challenge in database
|
||||
const challengeRecord: StoredChallenge = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue