How to implement two-factor authentication (2FA) in Node.js with authenticator apps
Learn how to implement two-factor authentication (2FA) in Node.js using authenticator apps, TOTP, and the otplib library. This step-by-step guide covers everything from generating QR codes to verifying authentication codes.
What is two-factor authentication (2FA)
In traditional applications, we typically use Email/Username/Phone as our identity identifiers. By combining these identity identifiers with corresponding passwords or verification codes, we can complete the process of authentication.
However, in scenarios with higher security requirements, relying solely on identity identifiers for authentication is not enough. This is because these identity identifiers and their corresponding verification information may be vulnerable to leaks.
This is where two-factor authentication (2FA) comes in - an additional security layer that requires users to provide two different authentication factors to verify their identity, ensuring that the person attempting to access the account is truly the legitimate user.
Common 2FA methods include:
- TOTP authentication using authenticator apps
- Biometric authentication
- Device-based authentication
- SMS verification codes
In this tutorial, we'll focus on implementing TOTP-based 2FA using authenticator apps using the otplib library in your Node.js application.
What is TOTP Authentication?
TOTP stands for Time-based one-time passwords. As the Wikipedia says, it is a computer algorithm that generates a one-time password (OTP) that uses the current time as a source of uniqueness.
With a shared TOTP secret key between the user's phone and the app server, the user's phone and the app server can generate the same TOTP code at the same point in time:
As TOTP generation relies on time, it can be calculated offline. Additionally, TOTP produces a numerical string, making it simple and user-friendly. Therefore, verifying TOTP is commonly used as a means of 2-factor authentication.
When users use TOTP as a 2-factor authentication method, they often encounter the challenge of storing the TOTP secret and generating TOTP codes. This is where authenticator apps come in handy. We can use authenticator apps to store the TOTP secret and authenticator apps will automatically generate TOTP codes for you. When verification is needed, you just have to open your authenticator app, and you will get the TOTP code corresponding to the TOTP secret. Popular Authenticator apps include Google Authenticator and Microsoft Authenticator.
The process of implementing TOTP as two-factor authentication involves two steps:
- Binding a TOTP secret to the user.
- Verifying the user's TOTP code by the related TOTP secret.
The process of binding TOTP to a user is as follows:
Once the user has bound TOTP, they can use it for verification. The process is as follows:
As illustrated in the diagram,on the user side, we use authenticator apps to manage the TOTP secret and generate TOTP codes. On the server side, we need to support generating a TOTP secret and validating the TOTP code sent by the user. In this article, we will use otpllib as an example to integrate TOTP-related functionalities on the server side.
Implement TOTP-based 2FA using otplib for your Node.js app
Assuming your app is based on Express.js, and users log in through the /sign-in
endpoint, the plan to support TOTP in the user login process is as follows:
- When the user is not bound to TOTP, send the TOTP secret to the user in the form of a QR code and prompt them to bind TOTP.
- When the user has already bound TOTP, prompt them to verify TOTP.
First, let's install the dependencies for the project: otplib
and qrcode
:
Next, let's enhance our /sign-in
endpoint.
According to our implementation, when a user is not bound to TOTP, we will send a QR code to the frontend:
The user scans the QR code with the authenticator app, and the authenticator app will generate a TOTP code and store the related TOTP secret.
The user sends the obtained TOTP code back to the app server. If the code is successful verified, we can then bind this TOTP to the user.
So, let's implement a /verify-totp
API to receive the TOTP code sent by the user:
This way, we have successfully bound TOTP for the user. Subsequently, when the user logs in, they only need to open the Authenticator App, send the verification code corresponding to the previously bound TOTP secret, and the authentication process will be completed.
In the /verify-totp
API, we use the TOTP secret previously bound to the user to verify the TOTP code.
Summary
Based on this article, you should now be able to integrate authenticator app verification for your apps.
However, this is just a simple example. When your app is large or expected to become complex, integrating a new authentication method may incur significant costs.
The great news is: Logto, serving as a comprehensive identity authentication solution provider, offers multi-factor authentication (MFA) support, including authenticator app verification. By leveraging Logto, you can seamlessly integrate a secure and efficient user login process with MFA into your application in just a few minutes!