I am trying to use my passkey for login in my react.js app using node.js for backend and using MongoDB for my database.
following is my backend code:
const registerWebAuthentication = async (req, res) => {
console.log("------------------------>>>>",req.body);
try {
const user = await User.findOne({ username: req.body.username });
console.log("from registerWebauthentication: " + req.body);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const challengePayload = await SimpleWebAuthnServer.generateRegistrationOptions({
rpID: 'localhost',
rpName: 'nobil localhost',
userName: user.username,
})
await User.findOneAndUpdate(
{ username: req.body.username },
{ challenge: challengePayload.challenge }
);
return res.json({ options: challengePayload })
} catch (e) {
console.log(e);
}
}
const verifyRegistration = async(req, res) => {
console.log("inside verify registrations ===========>>", req.body);
try {
const user = await User.findOne({ username: req.body.username });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const expectedChallenge = user.challenge;
const verification = await SimpleWebAuthnServer.verifyRegistrationResponse({
response: req.body.cred,
expectedChallenge: expectedChallenge,
expectedOrigin: 'http://localhost:3000',
expectedRPID: 'localhost',
});
if (!verification.verified) return res.json({ error: 'could not verify' });
await User.findOneAndUpdate(
{ username: req.body.username },
{ passkey: verification.registrationInfo }
);
return res.json({ verified: true });
} catch (e) {
console.log(e);
}
}
and following is my code to login in backend:
const registerWebAuthentication = async (req, res) => {
console.log("------------------------>>>>",req.body);
try {
const user = await User.findOne({ username: req.body.username });
console.log("from registerWebauthentication: " + req.body);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const challengePayload = await SimpleWebAuthnServer.generateRegistrationOptions({
rpID: 'localhost',
rpName: 'nobil localhost',
userName: user.username,
})
await User.findOneAndUpdate(
{ username: req.body.username },
{ challenge: challengePayload.challenge }
);
return res.json({ options: challengePayload })
} catch (e) {
console.log(e);
}
}
const verifyRegistration = async(req, res) => {
console.log("inside verify registrations ===========>>", req.body);
try {
const user = await User.findOne({ username: req.body.username });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const expectedChallenge = user.challenge;
const verification = await SimpleWebAuthnServer.verifyRegistrationResponse({
response: req.body.cred,
expectedChallenge: expectedChallenge,
expectedOrigin: 'http://localhost:3000',
expectedRPID: 'localhost',
});
if (!verification.verified) return res.json({ error: 'could not verify' });
await User.findOneAndUpdate(
{ username: req.body.username },
{ passkey: verification.registrationInfo }
);
return res.json({ verified: true });
} catch (e) {
console.log(e);
}
}
I am handling the logging in my frontend component as follows:
const handlePasskeyLogin = async () => {
try {
const res = await Axios.post('/generate-login-options', { username: passkeyUsername });
console.log("following are the options: ", res);
const options = res.data.options;
const loginRes = await startAuthentication(options);
console.log(loginRes);
const verifyRes = await Axios.post('/verify-passkey-login', { username: passkeyUsername, cred: loginRes });
console.log("response from server on verification of passkey login: ", verifyRes);
// if (verifyRes.data.verified) {
// setAdvertiser(verifyRes.data.user);
// setSigned(true);
// navigate("/home");
// } else {
// notify("Passkey login failed");
// }
if(verifyRes.data.role === "display-provider"){
localStorage.setItem("Dp_token", verifyRes?.data?.token);
}
else{
localStorage.setItem("token", verifyRes?.data?.token);
}
console.log(verifyRes?.data?.token);
sessionStorage.setItem("role", verifyRes.data);
localStorage.setItem("Admin", verifyRes.data.DpUsername);
console.error("An error occurred:", verifyRes?.status);
if (verifyRes?.status === 200) {
setAdvertiser(verifyRes.data)
sessionStorage.setItem("role", verifyRes.data.role);
setSigned(true);
navigate("/home");
}
else if (verifyRes?.status === 202) {
setSigned(true);
if (verifyRes.data.role === "Manager") {
sessionStorage.setItem("role", verifyRes.data.role);
navigate("/Manager");
} else if (verifyRes.data.role === "Publisher") {
sessionStorage.setItem("role", verifyRes.data.role);
navigate("/Publisher");
} else if (verifyRes.data.role === "Viewer") {
sessionStorage.setItem("role", verifyRes.data.role);
navigate("/Viewer");
}
}
} catch (error) {
console.error(error);
notify("Error during passkey login");
}
};
whenever I am trying to log in, the following error shows up in my backend server:
Error: No data
at Object.decodePartialCBOR (C:UsersnobilOneDriveDesktopMOLOGEveridoorBackend2.0node_modules@levischucktiny-cborscriptcborcbor.js:355:15)
at Object.decodeFirst (C:UsersnobilOneDriveDesktopMOLOGEveridoorBackend2.0node_modules@simplewebauthnserverscripthelpersisoisoCBOR.js:25:40)
at decodeCredentialPublicKey (C:UsersnobilOneDriveDesktopMOLOGEveridoorBackend2.0node_modules@simplewebauthnserverscripthelpersdecodeCredentialPublicKey.js:6:84)
at verifySignature (C:UsersnobilOneDriveDesktopMOLOGEveridoorBackend2.0node_modules@simplewebauthnserverscripthelpersverifySignature.js:20:86)
at Object.verifyAuthenticationResponse (C:UsersnobilOneDriveDesktopMOLOGEveridoorBackend2.0node_modules@simplewebauthnserverscriptauthenticationverifyAuthenticationResponse.js:157:66)
at async verifyLogin (C:UsersnobilOneDriveDesktopMOLOGEveridoorBackend2.0controllersuser.controller.js:147:26)
POST /verify-passkey-login 500 52.308 ms - 35
I am doing everything according to official documentation here: https://simplewebauthn.dev/docs/packages/server
please help me