Type Here to Get Search Results !

Add Biometric authentication in Node JS

Add Biometric authentication in Node JS

In today’s digital age, ensuring robust security for applications is paramount. One effective method is implementing fingerprint security…

Biometric Authentication

Add Biometric authentication in Node JS

In today’s digital age, ensuring robust security for applications is paramount. One effective method is implementing fingerprint security using WebAuthn. This blog will walk you through adding fingerprint authentication in a Node.js application using the SimpleWebAuthn library. We will cover both frontend and backend code to give you a complete understanding of the implementation.

Prerequisites

  1. Basic understanding of Node.js and Express.js.
  2. Familiarity with jQuery for handling AJAX requests.
  3. A working Node.js environment.

Frontend Implementation

Let’s start by setting up the frontend. We’ll use jQuery to handle AJAX requests for registering and authenticating fingerprints.

Registering a Fingerprint

The following code handles the registration of a fingerprint:

<script src="https://unpkg.com/@simplewebauthn/browser/dist/bundle/index.umd.min.js"></script>
<script src="https://unpkg.com/@simplewebauthn/browser/dist/bundle/index.umd.min.js"></script>
function registerPasskey() {
$.ajax({
type: "POST",
url: "/api/auth/register-challenge",
success: async function (res) {
if (res.code == 200) {
const authenticationResult = await SimpleWebAuthnBrowser.startRegistration(res.data);
if (authenticationResult) {
$.ajax({
type: "POST",
url: "/api/auth/verify-challenge",
contentType: "application/json",
dataType: "json",
data: JSON.stringify({
challenge: res.data.challenge,
credential: authenticationResult,
}),
beforeSend: function () {
$("#register-passkey-btn").text("Registering...");
},
complete: function () {
$("#register-passkey-btn").hide();
},
success: function (res) {
if (res.code == 200) {
toastr.success(res.message);
checkBiometric();
} else {
toastr.error(res.message);
}
},
});
}
} else {
toastr.error(res.message);
}
},
});
}

Logging in with Fingerprint

The following code handles logging in using a fingerprint:

function biometricLogin() {
if ($("#devices").val() == "fingerprint") {
$.ajax({
type: "POST",
url: "/api/auth/login-challenge",
success: async function (data) {
if (data.checkFingerPrint == "false") {
toastr.error("Please register biometric first");
return;
}
if (data.code == 200) {
const challenge = data.data;
const authenticationResult = await SimpleWebAuthnBrowser.startAuthentication(challenge);
$.ajax({
type: "POST",
url: "/api/auth/verify-login-challenge",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
challenge: data.challenge,
credential: authenticationResult,
}),
success: function (data) {
if (data.code == 200) {
window.location.href = "/dashboard";
} else {
$("#alert").html(data.message).addClass("shake");
resetRecaptcha();
}
},
});
} else {
$("#alert").html(data.message).addClass("shake");
resetRecaptcha();
}
},
});
}
}

Backend Implementation

Now, let’s move on to setting up the backend. We will use the SimpleWebAuthn library to handle the WebAuthn protocol.

Dependencies

First, install the required dependencies:

npm install @simplewebauthn/server

Setting Up Routes

Below are the backend routes for registering and verifying fingerprints.

Register Challenge Route

This route generates a registration challenge:

const { generateRegistrationOptions, verifyRegistrationResponse } = require("@simplewebauthn/server");
const express = require('express');
const router = express.Router();

router.post("/register-challenge", async (req, res) => {
try {
const challengePayload = await generateRegistrationOptions({
rpID: "localhost",
rpName: "My Application",
userName: req.user.id,
});

if (challengePayload) {
res.json({ code: 200, data: challengePayload, status: "success" });
} else {
res.json({ code: 500, message: "Something went wrong. Please contact your administrator.", status: "error" });
}
} catch (err) {
console.error(err);
res.status(500).json({ message: "Internal Server Error" });
}
});

Verify Challenge Route

This route verifies the registration challenge response:

router.post("/verify-challenge", async (req, res) => {
try {
const verificationResult = await verifyRegistrationResponse({
expectedChallenge: req.body.challenge,
expectedOrigin: "https://myapp.example.com",
expectedRPID: "myapp.example.com",
response: req.body.credential,
});

if (verificationResult.verified) {
// Save the fingerprint information to the database
await saveFingerprint(req.user.id, verificationResult.registrationInfo);
res.json({ code: 200, status: "success", message: "Biometric Registration Successful!" });
} else {
res.json({ code: 500, message: "Invalid user!", status: "error" });
}
} catch (err) {
console.error(err);
res.status(500).json({ message: "Internal Server Error" });
}
});

Login Challenge Route

This route generates an authentication challenge:

const { generateAuthenticationOptions, verifyAuthenticationResponse } = require("@simplewebauthn/server");

router.post("/login-challenge", async (req, res) => {
try {
const user = await getUser(req.user.id); // Fetch the user from the database
if (!user || !user.fingerprint) {
return res.json({ code: 500, message: "Please register biometric first", status: "error", checkFingerPrint: "false" });
}

const options = await generateAuthenticationOptions({
rpID: "myapp.example.com",
userVerification: "preferred",
});

res.json({ code: 200, data: options, challenge: options.challenge, status: "success", checkFingerPrint: "true" });
} catch (err) {
console.error(err);
res.status(500).json({ message: "Internal Server Error" });
}
});

Verify Login Challenge Route

This route verifies the authentication challenge response:

router.post("/verify-login-challenge", async (req, res) => {
try {
const user = await getUser(req.user.id); // Fetch the user from the database

if (!user || !user.fingerprint) {
return res.json({ code: 500, message: "Fingerprint not found", status: "error" });
}

const result = await verifyAuthenticationResponse({
expectedChallenge: req.body.challenge,
expectedOrigin: "https://myapp.example.com",
expectedRPID: "myapp.example.com",
response: req.body.credential,
authenticator: JSON.parse(user.fingerprint),
});

if (result.verified) {
res.json({ code: 200, status: "success", message: "Login Successful!" });
} else {
res.json({ code: 500, message: "Invalid user!", status: "error" });
}
} catch (err) {
console.error(err);
res.status(500).json({ message: "Internal Server Error" });
}
});

Conclusion

Implementing fingerprint security in your Node.js application using WebAuthn is a robust way to enhance security. By following the steps outlined in this guide, you can add fingerprint authentication to your application, providing users with a secure and convenient login method.

Make sure to customize the dummy data, URLs, and database interactions to fit your application’s specific needs. Happy coding!

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.

Top Post Ad

Below Post Ad