Enhancing NodeJS authentication using Google Authenticator for MFA
Enhance security in your Node.js application with Multi-Factor Authentication (MFA) using Google Authenticator. This guide walks you through generating MFA secrets, creating QR codes, and verifying tokens, adding a crucial layer of protection beyond usernames and passwords. Secure your app today!

In today’s digital landscape, ensuring the security of user accounts is more crucial than ever. One effective way to enhance security is through Multi-Factor Authentication (MFA), which adds an additional layer of protection beyond just usernames and passwords. This blog post will guide you through the implementation of MFA in a Node.js application using Google Authenticator, a popular tool for generating time-based one-time passwords (TOTP).
Why Use Multi-Factor Authentication?
MFA helps prevent unauthorized access to user accounts by requiring more than one form of verification. This typically includes:
- Something you know: Your password.
- Something you have: A device, such as your phone, that can generate a TOTP.
By incorporating MFA, even if a password is compromised, an attacker would still need the second factor to gain access to the account, significantly enhancing security.
Overview of the Implementation
The implementation consists of two main parts:
- Generating MFA Secrets and QR Codes:
This step allows users to generate a secret key, which they can then use to add your application to their Google Authenticator app on their phone. They can either save the secret or scan the generated QR code to enable Time-Based One-Time Password (TOTP) verification. - Verifying MFA Tokens:
After adding your application to their authenticator app, users will need to enter the generated TOTP into your application during the login process. This token is then verified on the server to ensure that the user is authorized.
Let’s take a closer look at how each of these parts works and how they integrate seamlessly to enhance security.
1. Generating MFA Secrets and QR Codes
The first step in implementing Multi-Factor Authentication (MFA) involves generating a secret key for the user and creating a QR code { uses the secret key } that can be scanned by an authenticator app like Google Authenticator. Below is the breakdown of the process.
We will use speakeasy
for generating the secret key like this
const secret = speakeasy.generateSecret({ length: 20 });
Then, we can use the secret key to generate an QR Code image that can be scanned by an authenticator.
// Generate QR code for the authenticator app
const otpAuthUrl = speakeasy.otpauthURL({
secret: secret.base32,
label: userInfo.email_address,
issuer: "Dummy App",
encoding: "base32",
});
const imageUrl = await generateQRCodeImage(otpAuthUrl);
The otpAuthUrl
is nothing but the data that you want to display in the Authenticator about your Application.
- issuer: it is the name that will be displayed in the Google Authenticator for your Application for this case Dummy App.

And one more thing you need to do is save the secret code in the database for the particular user. This way you will be able to match the TOTP later.
const mfaSecret = new MFASecretModel({
email_address: userInfo?.email_address,
secret: secret.base32,
app: app,
status: "active",
});
2. Verifying MFA Tokens
Once the MFA secret is generated and the QR code is provided to the user, the next step is to verify the token provided by the user during the login process.
Here’s how you can verify the TOTP token:
const mfaSecret = await MFASecretModel.findOne({
email_address: userInfo?.email_address,
app,
status: "active",
});
// Verify token
const verified = speakeasy.totp.verify({
secret: mfaSecret.secret,
encoding: "base32",
token: token,
});
You will need to fetch the secret key as per the user and app that they have used. And then match the TOTP token through speakeasy.totp.verify()
method. This will return a boolean of true or false.
You can use these code snippets in your controllers as per your need. One use case is verify the TOTP after the user logs in if the user have added an authenticator app already or ask the user to enable two factor authentication for improving security.
export const loginUser = async (req: Request, res: Response) => {
try {
const { login_id, password } = req.body;
const user = await UserModel.findOne({
$or: [{ email_address: login_id }, { username: login_id }],
});
if (!user) {
return res.status(404).json({ error: "User not found" });
}
const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) {
return res.status(401).json({ error: "Invalid password" });
}
// Check if 2FA is enabled
const mfaSecret = await MFASecretModel.findOne({
email_address: user.email_address,
status: "active",
});
if (mfaSecret) {
return res.status(200).json({
message: "2FA enabled, please verify your TOTP",
twoFactorEnabled: true,
});
}
// Generate tokens and log in the user
const tokenDetails = {
userId: user._id,
username: user.username,
};
const accessToken = jwt.sign(tokenDetails, process.env.SECRET_KEY || "", {
expiresIn: "1d",
});
res.json({ accessToken });
} catch (error) {
console.error("Error during login:", error);
res.status(500).json({ error: "Internal server error" });
}
};
By implementing Multi-Factor Authentication using Google Authenticator in your Node.js application, you significantly enhance the security of user accounts. This method is straightforward to integrate and can be adapted to work with various authenticator apps. The addition of a second layer of security not only bolsters user trust but also safeguards sensitive information from unauthorized access.
As cyber threats continue to evolve, adopting security measures like MFA is crucial for protecting user data. Should you have any questions or need further assistance with implementing MFA in your Node.js application, don’t hesitate to reach out. Together, we can ensure a safer digital experience for your users.
That's it for today, See ya 👋.