Close Menu
Soshace Digital Blog

    Subscribe to Updates

    Get The Latest News, Updates, And Amazing Offers

    What's Hot
    Remote Job

    Ultimate Onboarding Checklist for Web Developers (Bonus: Onboarding Checklist for Freelancers)

    SaaS & Tech

    Maximizing Impact: Strategies for SaaS & Technology Marketing

    Beginners

    Operating Systems Showdown: Windows vs. macOS vs. Linux for Web Development

    Important Pages:
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Today's Picks:
    • Scaling Success: Monitoring Indexation of Programmatic SEO Content
    • Leveraging Influencers: Key Drivers in New Product Launches
    • How Privacy-First Marketing Will Transform the Industry Landscape
    • The Impact of Social Proof on Thought Leadership Marketing
    • Balancing Value-Driven Content and Promotional Messaging Strategies
    • Top Influencer Marketing Platforms to Explore in 2025
    • Emerging Trends in Marketing Automation and AI Tools for 2023
    • Strategies to Mitigate Duplicate Content in Programmatic SEO
    Thursday, October 23
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Soshace Digital Blog
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Services
    • SaaS & Tech

      Maximizing Efficiency: How SaaS Lowers IT Infrastructure Costs

      August 27, 2025

      Navigating Tomorrow: Innovations Shaping the Future of SaaS

      August 27, 2025

      Maximizing Impact: Strategies for SaaS & Technology Marketing

      August 27, 2025
    • AI & Automation

      Enhancing Customer Feedback Analysis Through AI Innovations

      August 27, 2025

      Navigating the Impact of AI on SEO and Search Rankings

      August 27, 2025

      5 Automation Hacks Every Home Service Business Needs to Know

      May 3, 2025
    • Finance & Fintech

      Critical Missteps in Finance Marketing: What to Avoid

      August 27, 2025

      Analyzing Future Fintech Marketing Trends: Insights Ahead

      August 27, 2025

      Navigating the Complex Landscape of Finance and Fintech Marketing

      August 27, 2025
    • Legal & Compliance

      Exploring Thought Leadership’s Impact on Legal Marketing

      August 27, 2025

      Maximizing LinkedIn: Strategies for Legal and Compliance Marketing

      August 27, 2025

      Why Transparency Matters in Legal Advertising Practices

      August 27, 2025
    • Medical Marketing

      Enhancing Online Reputation Management in Hospitals: A Guide

      August 27, 2025

      Analyzing Emerging Trends in Health and Medical Marketing

      August 27, 2025

      Exploring Innovative Content Ideas for Wellness Blogs and Clinics

      August 27, 2025
    • E-commerce & Retail

      Strategic Seasonal Campaign Concepts for Online and Retail Markets

      August 27, 2025

      Emerging Trends in E-commerce and Retail Marketing Strategies

      August 27, 2025

      Maximizing Revenue: The Advantages of Affiliate Marketing for E-Commerce

      August 27, 2025
    • Influencer & Community

      Leveraging Influencers: Key Drivers in New Product Launches

      August 27, 2025

      Top Influencer Marketing Platforms to Explore in 2025

      August 27, 2025

      Key Strategies for Successful Influencer Partnership Negotiations

      August 27, 2025
    • Content & Leadership

      The Impact of Social Proof on Thought Leadership Marketing

      August 27, 2025

      Balancing Value-Driven Content and Promotional Messaging Strategies

      August 27, 2025

      Analyzing Storytelling’s Impact on Content Marketing Effectiveness

      August 27, 2025
    • SEO & Analytics

      Scaling Success: Monitoring Indexation of Programmatic SEO Content

      August 27, 2025

      Strategies to Mitigate Duplicate Content in Programmatic SEO

      August 27, 2025

      Effective Data Visualization Techniques for SEO Reporting

      August 27, 2025
    • Marketing Trends

      How Privacy-First Marketing Will Transform the Industry Landscape

      August 27, 2025

      Emerging Trends in Marketing Automation and AI Tools for 2023

      August 27, 2025

      Maximizing ROI: Key Trends in Paid Social Advertising

      August 27, 2025
    Soshace Digital Blog
    Blog / JavaScript / Node.js / Implementing Two-Factor Authentication with NodeJS and otplib
    JavaScript

    Implementing Two-Factor Authentication with NodeJS and otplib

    bradstarartBy bradstarartJune 11, 2020Updated:May 25, 2023No Comments11 Mins Read
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    Implementing Two-Factor Authentication with NodeJS and otplib
    Implementing Two-Factor Authentication with NodeJS and otplib
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link

    There’s probably no better time to integrate two-factor authentication into your a than today.

    Two-factor authentication (often abbreviated TFA or 2FA) is a method of authenticating clients that involves ‘two factors’ when verifying a user – a password and something the user can physically access – like a fingerprint or a random SMS code (or even better, a one-time password!).

    Single-factor authentication refers to the kind of login that only requires a username (or email) and password. This is the traditional method of logging in that you’re probably used to.

    Before we get lost in a whole mess of new words, let’s break down some of the important vocabulary that will make it much easier to discuss upcoming concepts.

    One Time Password

    A one-time password is a kind of token (a code or word) that can only be used once. Regardless of how it’s implemented, such a password should only ever be valid for a single use case, then gets disregarded. It can never be used twice.

    You may already have spotted the giant bottleneck in implementing a robust OTP system. How can we ensure we only ever generate a unique token?

    The answer lies in the HMAC-based One-Time Password algorithm.

    Hmac-based One-Time Password algorithm (HOTP)

    The HOTP algorithm depends on two pieces of information in order to produce a token we can reliably use – a moving factor and a secret key.

    The secret key is probably something you’ve encountered in one form or another on some corner of the internet. It’s a token that’s shared between a server and client so we can be sure the client has somehow been granted access. Since the server is responsible for generating the tokens, the first problem we have is sharing the secret key with the client.

    The second problem we have is generating a random string on the server as our counter moves upwards. This counter is the mysterious-sounding ‘moving-factor’.

    In pseudocode:

    when counter = 1
         secret = xyz
         token = xyxyxyxyxyxy
    
    when counter = 2
         secret - xyz
         token = xxyyxxyyxxyy
    
    and so on...
    

    The ‘secret’ is a HmacSHA1 hash (published as RFC4226 by the Internet Engineering Task Force) of the actual secret string passed to the algorithm. The resulting output is about 20 bytes long. The second step is making the output short enough to be easily read by human eyes. This truncation is handled by the TOTP algorithm and can produce any string of our desired length, eg, “556 221″

    Great! Now we have a nice readable token that can be given to the user. The only problem that remains is the counter. Take a second to consider it before you throw in a simple auto-incrementing counter and call it a day

    The counter has to be implemented such that it never repeats itself or the same secret token will be generated twice at some point. If this happens, it’s a huge security vulnerability. To keep it short, implementing your own counter is a pain and you shouldn’t do it unless you’re sure you know what you’re doing.

    The solution to a bulletproof counter lies in literally using time’ as our counter. This then gives birth to the fabled time-based one-time password (TOTP)

    Time-based One Time Password (TOTP)

    Now we know the specifics of how a OTP comes about, let’s break it down even further to make sure they’re no blind spots in our implementation. If you’re interested in the technical bits, The “Time-Based One-Time Password” spec was published as RFC6238 by the IETF.
    The HOTP and TOTP algorithm only differ in the fact that the latter uses time as a counter. Since both server and client have access to time, there’s no need to create and manually keep track of a counter. The epoch time (when the counter begins, can be specified as a unix timestamp if time zones are going to be a problem).

    Time step

    Unix time is defined in seconds (which means our counter changes every second), which isn’t ideal. A better idea would be to generate the token after a significant time interval. We will call this time interval the time step.

    Read More:  The Ultimate Guide to Drag and Drop Image Uploading with Pure JavaScript

    In order to create the required interval, we’ll redefine our counter as

    counter = currentUnixTime/30

    A larger time step means that your app (and your users) will have a longer time to validate a new token before the old one is invalidated. However, this also means a larger attack opportunity for attackers – the key is balance.

    Delay window

    Another important concept that needs to be introduced is the delay window. What happens if the client sends a TOTP that’s close to expiry, but due to a latency issue, it arrive at the server after expiry? Do we reject such a token and require the user to generate a new one? We could, but a better idea is to create a delay window.

    A delay window makes the TOTP validation function not only check tokens that are valid for the current step but also for the last S steps. Since the counter we are using is predictable, we can also predict what tokens will be generated in the future. The delay window can thus verify tokens from both the past and the future.

    Delay widow and time step are both important concepts to have at your fingertips. Since our client is going to be Google Authenticator or a similar 2FA app, we don’t have to worry about them. These are built-in. (GA’s time-step is 30 seconds).

    Sharing the secret with the user

    Finally, we need a way to share the secret generated on the server with our client. This should ideally be a random (secure) string. Since we want it to be very long, having the user input it manually would be a pain. Instead, we’ll leverage QR codes!

    Implementing Two Factor Authentication with NodeJS

    Now that all the theory is done, you should have a solid understanding of one of the most important algorithms on the web. We should get down to implementing it with express and NodeJS. We’re going to use a fairly old and well-supported library – otplib.

    For the sake of keeping this tutorial short and to the point, we won’t implement actual login logic for this app. That would mean setting up a database in addition to a server, and that’s outside the scope of this article.

    Here’s how the app is going to work

    Setting up

    Step 1: A user enables 2FA

    It’s important to note that the user has to explicitly enable two-factor authentication for it to work. Recall that the secret has to be shared between the server and client.

    When the user enables 2FA, we generate a unique secret key for them:

    import {authenticator} from ‘otplib’
    const secret = authenticator.generate() // only available for google authenticator or similar
                                            // use crypto.randomBytes otherwise

    The secret should be stored in the database together with the user that owns it.

    Step 2: Share the secret with the user

    Note: Google Authenticator ignores the ‘algorithm’, ‘digits’, and ‘step’ options supported by otplib. Cross-check with your authenticator app in case of errors.

    The second step is finding a way we can give the client access to the secret generated by the server. Since most modern phones have cameras, a QR code is a convenient way of encoding our (inconveniently long) string so that the user doesn’t have to type it out.

    To do this, we’ll use the qrcode module.

      {
       //...
       generateQRCode: (user, secret) => {
    
            const otp = authenticator.keyuri(user, "Our TFA App", secret);
            let imagePath = '';
    
            qrcode.toDataURL(otp, (err, imageUrl) => {
                if (err) {
                    console.log('Could not generate QR code', err);
                    return;
                }
                imagePath = imageUrl;
            });
            return imagePath;
    
        }
    //...
    }

    Once the image path is generated, share it with the user over your API.

    In order to confirm the QR code was scanned, you could ask the user to input their fresh TOTP code. This can be verified using:

    {
    //...
        verify: (token, secret)=> authenticator.verify({secret, token}),
    //...
    }

    Logging In

    Step 1: Username and password

    The first step of a 2FA flow resembles everything you’re probably used to by now: the user first provides their username and password. The server is then responsible for verifying that the specified user exists in the database. If both username and email are correct, the API should next check if 2FA is enabled for the account.

    Read More:  TOP 11 JavaScript Machine Learning & Data Science Libraries

    Should 2FA be active for the account, the server should serve a simple reply such as “2FAEnabled:true”. This tells the client to send the same request again (this time to a new ‘/verify’ route) with the necessary token. The client might have to persist the credentials, but since you’re dealing with potentially sensitive data, be careful with how you store it.

    If you’re uncomfortable with having a password that exposed, the server could also generate a special short-lived token that’s only valid for the ‘/verify’ route. This token (and response body) is sent to the client, who saves it.

    app.post('/login', (req, res) => {
        const user = req.user;
    
        //Do some validation to make sure username and password exist
        // Check that the email exists
        if (user.existsInDatabase){
            // Check to see if email and password are valid
            // If email and password are valid, check if 2fa is enabled
            if (user.hasCorrectCredentials) {
                if (user.is2FAEnabled) {
                    return res.status(200).send({
                        shortLivedToken: 'xxyy', // this shouldn't be a normal access token that can be used elsewhere in the app
                        is2FAEnabled: true
                    })
                }
            }
        }
    });

    Step 2: Verifying the TOTP

    Once the client has received a response indicating 2FA has been enabled, the site or app should redirect the user to a second page or show a dialog requesting a TOTP code. Depending on how you’ve decided to implement it, the server authorizes the client based on the short-lived token or by re-sending the username and password.

    The final step will look something like:

    app.post('/login/verify', (req, res)=> {
        const otpToken = req.body.otpToken;
        const accessToken = req.headers["Authorization"];
        const user = req.user;
    
        if (accessToken.isValid) {
            const isOTPTokenValid = verify(otpToken, user.secret);
            if (isOTPTokenValid) {
                res.status(200).send({
                    accessToken: '' //jwt generate token. This is a normal token that can be used to log in.
                })
            }
        }
    })

    If the user provides the right TOTP code, we provide them with a normal access token that can be used to access other parts of the app!

    Bonus update: Generating recovery keys

    What happens if one of your users says they lost their phone, and thereby access to their authenticator app, so they can’t log in? The most common practice is to allow users to generate recovery keys. If they no longer have access to their authenticator app, they are allowed to use one of these recovery keys to effectively reset the two-factor authentication status as tracked by your application.

    There are a few simple rules to be followed when it comes to generating and handling recovery keys.

    • The recovery keys should be long enough that they aren’t easy to guess or crack through a dictionary attack.
    • They should be treated like one-time passwords. Once they are used, they need to be discarded.
    • Just like one-time passwords, they should be encrypted before being stored on the database. This way, if an intruder ever gains access to your database, the codes they gain access to are practically useless. The downside to this is that your users can only ever see (or download) their codes once. If the codes are lost, they have to be regenerated.

    Conclusion

    Two-factor authentication adds a layer of protection to your authentication mechanism. However, it will ultimately become useless if you attempt to treat it as a solution to all your problems.

    • Both the normal login and ‘/verify’ routes should be protected from brute forcing. If someone decides to take down your 2FA system, logging in might turn out to be impossible.
    • Be careful with the delay window and time step options. You don’t want your TOTP codes to be valid for too long.

    Link to the Github Repository with a project.

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    bradstarart

      Related Posts

      Streamlining Resource Allocation for Enhanced Project Success

      December 18, 2024

      Conducting Effective Post-Project Evaluations: A Guide

      December 16, 2024

      Strategies for Keeping Projects on Track and Meeting Deadlines

      December 10, 2024
      Leave A Reply Cancel Reply

      You must be logged in to post a comment.

      Stay In Touch
      • Facebook
      • Twitter
      • Pinterest
      • Instagram
      • YouTube
      • Vimeo
      Don't Miss
      JavaScript January 28, 2020

      Malesuada Proin Libero Nunc Consequat Interdum

      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore…

      Node.js Lesson 6: Util and Inheritance

      October 2, 2020

      Maximizing LinkedIn: Strategies for Legal and Compliance Marketing

      August 27, 2025

      Уроки React . Урок 9

      October 7, 2016

      Categories

      • AI & Automation
      • Angular
      • ASP.NET
      • AWS
      • B2B Leads
      • Beginners
      • Blogs
      • Business Growth
      • Case Studies
      • Comics
      • Consultation
      • Content & Leadership
      • CSS
      • Development
      • Django
      • E-commerce & Retail
      • Entrepreneurs
      • Entrepreneurship
      • Events
      • Express.js
      • Facebook Ads
      • Finance & Fintech
      • Flask
      • Flutter
      • Franchising
      • Funnel Strategy
      • Git
      • GraphQL
      • Home Services Marketing
      • Influencer & Community
      • Interview
      • Java
      • Java Spring
      • JavaScript
      • Job
      • Laravel
      • Lead Generation
      • Legal & Compliance
      • LinkedIn
      • Machine Learning
      • Marketing Trends
      • Medical Marketing
      • MSP Lead Generation
      • MSP Marketing
      • NestJS
      • Next.js
      • Node.js
      • Node.js Lessons
      • Paid Advertising
      • PHP
      • Podcasts
      • POS Tutorial
      • Programming
      • Programming
      • Python
      • React
      • React Lessons
      • React Native
      • React Native Lessons
      • Recruitment
      • Remote Job
      • SaaS & Tech
      • SEO & Analytics
      • Soshace
      • Startups
      • Swarm Intelligence
      • Tips
      • Trends
      • Vue
      • Wiki
      • WordPress
      Top Posts

      10 Hiring Lessons from Silicon Valley: for Small and Large Companies

      JavaScript January 31, 2019

      Effective Recruitment Strategies for Nonprofit Organizations

      Blogs November 24, 2024

      How to use the redux dev tools to speed up development and debugging

      React December 24, 2020

      Filtering, Sorting and Pagination – Advanced Filtering with React and Redux

      JavaScript March 18, 2020

      Subscribe to Updates

      Get The Latest News, Updates, And Amazing Offers

      About Us
      About Us

      Soshace Digital delivers comprehensive web design and development solutions tailored to your business objectives. Your website will be meticulously designed and developed by our team of seasoned professionals, who combine creative expertise with technical excellence to transform your vision into a high-impact, user-centric digital experience that elevates your brand and drives measurable results.

      7901 4th St N, Suite 28690
      Saint Petersburg, FL 33702-4305
      Phone: 1(877)SOSHACE

      Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
      Our Picks
      Beginners

      A Roundup Review of the Best Deep Learning Books

      JavaScript

      TOP 5 Latest Books for Hiring Best People in Tech (and Other Areas)

      Beginners

      Three Essential Rules for Architecting iOS Unit Tests in 2020

      Most Popular

      Leveraging Case Studies and Testimonials for B2B Leads

      B2B Leads

      Leveraging Video Recruiting to Attract Top Talent Effectively

      Recruitment

      23. Node.js Lessons. Domains, asynchronous try.. catch. Part 1.

      Programming
      © 2025 Soshace Digital.
      • Home
      • About
      • Services
      • Contact Us
      • Privacy Policy
      • Terms & Conditions

      Type above and press Enter to search. Press Esc to cancel.