Authentication flow change - Remove requirement for user to enter username - Use Passkey discoverability instead.

This commit is contained in:
Cameron Redmore 2025-04-26 08:32:54 +01:00
parent 0d277e3035
commit 7564937faa
8 changed files with 120 additions and 75 deletions

View file

@ -60,7 +60,7 @@ router.post('/generate-registration-options', async(req, res) =>
//Check if the registrationToken matches the setting
const registrationTokenSetting = await getSetting('REGISTRATION_TOKEN');
if (registrationTokenSetting !== registrationToken)
if (registrationTokenSetting !== registrationToken && !req.session.loggedInUserId)
{
return res.status(403).json({ error: 'Invalid registration token' });
}
@ -200,9 +200,6 @@ router.post('/verify-registration', async(req, res) =>
challengeStore.delete(userId);
delete req.session.userId;
// Log the user in by setting the final session userId
req.session.loggedInUserId = user.id;
res.json({ verified: true });
}
else
@ -243,27 +240,29 @@ router.post('/generate-authentication-options', async(req, res) =>
user = await getUserById(req.session.loggedInUserId);
}
if (!user)
{
return res.status(404).json({ error: 'User not found' });
}
// if (!user)
// {
// return res.status(404).json({ error: 'User not found' });
// }
const userAuthenticators = await getUserAuthenticators(user.id);
// const userAuthenticators = await getUserAuthenticators(user.id);
const options = await generateAuthenticationOptions({
rpID,
// Require users to use a previously-registered authenticator
allowCredentials: userAuthenticators.map(auth => ({
id: auth.credentialID,
type: 'public-key',
transports: auth.transports ? auth.transports.split(',') : undefined,
})),
// allowCredentials: userAuthenticators.map(auth => ({
// id: auth.credentialID,
// type: 'public-key',
// transports: auth.transports ? auth.transports.split(',') : undefined,
// })),
allowCredentials: [],
userVerification: 'preferred',
});
// Store the challenge associated with the user ID for verification
challengeStore.set(user.id, options.challenge);
req.session.challengeUserId = user.id; // Store user ID associated with this challenge
//Store challenge associated with random ID
const challengeId = crypto.randomUUID();
challengeStore.set(challengeId, options.challenge);
req.session.challengeUserId = challengeId; // Store user ID associated with this challenge
res.json(options);
}
@ -294,11 +293,11 @@ router.post('/verify-authentication', async(req, res) =>
try
{
const user = await getUserById(challengeUserId);
if (!user)
{
return res.status(404).json({ error: 'User associated with challenge not found' });
}
// const user = await getUserById(challengeUserId);
// if (!user)
// {
// return res.status(404).json({ error: 'User associated with challenge not found' });
// }
const authenticator = await getAuthenticatorByCredentialID(authenticationResponse.id);
@ -307,6 +306,12 @@ router.post('/verify-authentication', async(req, res) =>
return res.status(404).json({ error: 'Authenticator not found' });
}
const user = await getUserById(authenticator.userId);
if (!user)
{
return res.status(404).json({ error: 'User not found' });
}
// Ensure the authenticator belongs to the user attempting to log in
if (authenticator.userId !== user.id)
{