Google Authenticator is something that many of us use all the time but how many of us really understand how it works under the hood? In this tutorial, I will demystify the magic behind Google Authenticator’s expiring OTP codes and show you how to add Google Authenticator support to your application from scratch, in JavaScript. As part of career accelerator program, I got an opportunity to contribute to this amazing open-source project called . It lets you create stylish command line prompts that are user-friendly and easy to create. At the time of writing this article, Enquirer has upwards of 4500 Github stars and is used by more than 7500 other repositories. Pesto’s Enquirer One of the features I added to Enquirer was the ability to , without the need of an internet connection. verify time-based one-time passwords, directly from command-line, generated by any two-factor authentication application, such as Google Authenticator Why Time-based OTPs? Time-based OTP (TOTP) is an algorithm that factors in the current time to generate a unique one-time password. In today’s age, it is a no-brainer that passwords alone can’t keep the bad guys out. You need an additional layer of security — a second factor. There are many types of two-factor authentication systems, but for them to work, they must be both secure and user-friendly. TOTP ticks both boxes perfectly. It’s secure because: The password changes every n number of seconds (usually, 30 seconds), preventing eavesdroppers from using that same password later in the future if somehow they’re able to get hold of it. The password may be generated by an app on the user’s phone, making it more difficult for an attacker to acquire the password, as the user’s phone is usually by his/her side. It’s user-friendly because: In mobile app implementations, the user only needs to launch the TOTP application and then key-in the TOTP that appears on-screen into the application Unlike most mobile-based one-time passwords that need to be received via a text message or the Internet through some wireless connection, TOTPs aren’t dependent on the presence of a cellular signal or data connection. I used Google Authenticator as the mobile app to verify one-time passwords. Google Authenticator generates time-based OTPs which are calculated using the algorithm specified in . The app also supports HMAC-based OTPs calculated using the algorithm specified in . RFC6238 RFC4226 Time-based OTPs rely on the algorithm for HMAC-based OTPs (HOTPs). In this article, we’ll be implementing both the algorithms, using NodeJS (JavaScript). Generating Secret Firstly, we’ll have to create an application-specific secret key that will be used to verify OTPs. This will also be shared with the Google Authenticator app. The secret key is how the authenticator apps know what OTPs to generate for a specific app/website. The secret can be generated in many ways and this is one of the implementations. We’ll generate a completely random buffer of data using the in-built NodeJS library and then we’ll encode the data to base32 using . crypto hi-base32 npm module crypto = ( ); base32 = ( ); { randomBuffer = crypto.randomBytes(length); base32.encode(randomBuffer).replace( , ); } const require 'crypto' const require 'hi-base32' ( ) function generateSecret length = 20 const return /=/g '' This function will return a random string which is our secret key. Input this in the Google Authenticator app. We’ll be verifying the OTPs for this secret, using our implementation. Generating HMAC-based OTPs To generate HOTP we need a secret key and a counter value. We already have a secret. We don’t need to worry about counter as of now because we’ll be providing its value when we generate TOTPs. Let’s say our function that generates HOTP accepts two arguments, and . First, we’ll decode the secret. Basics secret counter decodedSecret = base32.decode.asBytes(secret); const Now we’ll create a buffer from the value. counter buffer = Buffer.alloc( ); ( i = ; i < ; i++) { buffer[ - i] = counter & ; counter = counter >> ; } const 8 for let 0 8 7 0xff 8 According to , we have three major steps to generate a HOTP. RFC4226 Google Authenticator uses SHA1 algorithm to create HMAC. We’ll use functions from the library to create an HMAC (using SHA1), update the above-created with this and then produce an HMAC value; Step 1 — Generate an HMAC value crypto buffer hmac = crypto.createHmac( , Buffer.from(decodedSecret)); hmac.update(buffer); hmacResult = hmac.digest(); const 'sha1' const is a 20-byte string which is an HMAC-SHA-1 value. hmacResult The purpose of dynamic truncation is to extract 4-byte dynamic binary code from a 20-byte HMAC-SHA-1 result. These steps are directly taken from . Step 2 — Dynamic Truncation RFC4226 offset = hmacValue[hmacValue.length - ] & ; code = ((hmacValue[offset] & ) << ) | ((hmacValue[offset + ] & ) << ) | ((hmacValue[offset + ] & ) << ) | (hmacValue[offset + ] & ); const 1 0xf const 0x7f 24 1 0xff 16 2 0xff 8 3 0xff Google Authenticator generates six-digit passwords, so we’ll extract the first six-digits of the to get our final HOTP value. Step 3 — Compute the HOTP value code hotp = code % ( ** ); const 10 6 Putting it all together, the generateHOTP function can be written as: crypto = ( ); base32 = ( ); { decodedSecret = base32.decode.asBytes(secret); buffer = Buffer.alloc( ); ( i = ; i < ; i++) { buffer[ - i] = counter & ; counter = counter >> ; } hmac = crypto.createHmac( , Buffer.from(decodedSecret)); hmac.update(buffer); hmacResult = hmac.digest(); code = dynamicTruncationFn(hmacResult); code % ** ; } { offset = hmacValue[hmacValue.length - ] & ; ( ((hmacValue[offset] & ) << ) | ((hmacValue[offset + ] & ) << ) | ((hmacValue[offset + ] & ) << ) | (hmacValue[offset + ] & ) ); } const require 'crypto' const require 'hi-base32' ( ) function generateHOTP secret, counter const const 8 for let 0 8 7 0xff 8 // Step 1: Generate an HMAC-SHA-1 value const 'sha1' const // Step 2: Generate a 4-byte string (Dynamic Truncation) const // Step 3: Compute an HOTP value return 10 6 ( ) function dynamicTruncationFn hmacValue const 1 0xf return 0x7f 24 1 0xff 16 2 0xff 8 3 0xff We have a function using which we can generate HMAC based one-time passwords. Now we can use this function to generate Time based one-time passwords. Generating Time-based OTPs The algorithm for time-based OTPs simply uses current (with a time-step of 30 seconds) as the value in the function. Unix time counter generateHOTP We can get the current time in JavaScript using . But this returns the number of milliseconds elapsed since . We have to convert the time-step of 1 millisecond to time-step of 30 seconds. Date.now() January 1, 1970, 00:00:00 UTC counter = .floor( .now() / ); const Math Date 30000 We also accept a argument which helps us get the TOTP of any time window from current time. So if we want to know what TOTP was generated before 2 minutes from now, we set . This calculates the TOTP at 4 time-steps (of 30 seconds each) before the current time. window window = -4 So, our function can be written as: generateTOTP { counter = .floor( .now() / ); generateHOTP(secret, counter + ); } ( ) function generateTOTP secret, window = 0 const Math Date 30000 return window Verifying Time-based OTPs To verify TOTPs generated on the Google Authenticator app, we need the secret key. Once we have the secret key we can use the function above and calculate the TOTP to see if it matches or not. generateTOTP Sometimes, it is possible that while a user is typing the OTP the current window of 30 seconds passes and the OTP she entered gets failed. To improve the user experience, we not only check the TOTP generated at the current time-step window but also one step before and one step after the current window. If the current time is T⁰, we'll verify the TOTP for these steps: T⁰ – 1 T⁰ T⁰ + 1 We can also use a wider window but doing so may be a security risk. If we use a window of T⁰ ± 20 , for example, this would mean that an OTP generated 10 minutes ago is still valid! Keeping this in mind, our function can be written as: verifyTOTP { ( .abs(+ ) > ) { .error( ); ; } ( errorWindow = - ; errorWindow <= + ; errorWindow++) { totp = generateTOTP(secret, errorWindow); (token === totp) { ; } } ; } ( ) function verifyTOTP token, secret, window = 1 if Math window 10 console 'Window size is too large' return false for let window window const if return true return false is the TOTP from Google Authenticator. We are invoking function to calculate the TOTPs for all windows and checking if it matches with the token entered. token generateTOTP This function returns if the token is successfully verified. This completes the implementation of Two Factor Authentication (TOTP) with Google Authenticator. true I’ve removed some error checking to keep this article simple. You can find the complete code at this . pull request Make sure you check out the library and drop a Github star. Thanks for reading! Enquirer Hi, my name is Rajat. I am a truly full-stack software engineer with experience working on everything from patching U-boot and Linux drivers in C to launching top-rated products on Product Hunt.