Time-based One-time Password (TOTP)?, How to use it in Ruby On Rails API?

Saleh AlhaddadSaleh Alhaddad
9 min read
  1. Intro

    Security is paramount in today's digital world. Two-factor authentication (2FA) adds an extra layer of protection beyond just usernames and passwords. While SMS OTP is a common 2FA method, it can be costly, but TOTP (Time-Based One-Time Password), is a free and secure alternative using authenticator apps like Google Authenticator. This subject dives into the world of TOTP 2FA, exploring its functionalities and implementation within Ruby on Rails applications.

  2. Authentication

    • The Essence of Authentication(Who Are You?):

      Authentication revolves around establishing a user's legitimacy. When you attempt to access a system, it needs to confirm that you are indeed the authorized user you claim to be. This verification process ensures that only rightful individuals access sensitive information or functionalities.

    • Methods of Authentication(Proving Your Identity):

      There are various ways to authenticate users. Here's a closer look at some common methods:

      • Knowledge-based: This involves providing a secret piece of information known only to the user and the system, such as a username and password combination.

      • Token-based: These methods involve a unique token, like a physical security key or a code generated by an authentication app, that verifies your identity.

      • Biometric: These methods rely on unique physical or physiological characteristics, such as fingerprints, facial recognition, or voice patterns, for user verification.

    • How Authentication Works(Behind the Scenes):

      Mechanics of authentication using the common username and password method:

      • Account Creation: You create a unique username and password to establish your identity within the system. These credentials are securely stored on the server.

      • Verification at Login: When you attempt to log in, you enter your username and password. The system retrieves the stored credentials associated with your username and compares them to the ones you entered.

      • Granting Access: If the provided credentials match the stored information, the system authenticates the user and grants access.

    • Authentication vs. Authorization(Understanding the Difference):

      • While authentication verifies who you are, authorization determines what you can do within a system. Authentication ensures you are a legitimate user, while authorization dictates the specific actions or resources you are allowed to access based on your assigned permissions.
    • Authentication Methods

      Authentication comes in various forms, each offering different levels of security. Let's explore the common ones:

      • Single-Factor Authentication (SFA): This is the simplest method, relying on a single credential like a username and password. While convenient, it's considered weak as compromising one-factor grants access.

      • Multi-Factor Authentication (MFA) strengthens online account security by requiring multiple verification methods for login, think of it like adding extra locks to your door.

      • Two-Factor Authentication (2FA) uses two factors:

        • Something you know (password or PIN).

        • Something you have (security token, smartphone app code, SMS/email code).

        • Example: Entering your bank password (something you know) and then a code from your banking app (something you have).

        • Example: SMS, TOTP, Pre-generated Code, push, and U2F security keys.

      • Three-Factor Authentication (3FA) adds another layer on top of 2FA:

        • Something you are (fingerprint, face recognition, iris scan).

        • Example: Using 2FA with fingerprint recognition for high-security applications.

      • Single Sign-On (SSO): This allows users to access multiple applications with one set of credentials (e.g., logging into other apps using Google or Facebook). While convenient, it relies on a trusted third party for authentication.

  1. TOTP

    • What is TOTP?

      TOTP, standing for Time-based One-Time Password, is a powerful and widely used method for two-factor authentication (2FA). It significantly enhances account security by requiring a unique, temporary code alongside your traditional username and password, the time-based passwords are available offline without connection to internet or have signal in mobile.

    • How Does TOTP Work?

      The magic of TOTP lies in its reliance on the current time and a shared secret between your device and the application you're trying to access. Here's a breakdown of the process:

      • Secret Sharing: During initial setup, the application generates a secret key. This key can be displayed as a QR code or a string of characters.

      • Authenticator App Integration: You scan the QR code or enter the secret key into a TOTP-compatible authenticator app on your smartphone (e.g., Google Authenticator, Microsoft Authenticator), also you can use your pc.

      • Code Generation: The authenticator app uses the secret key, along with the current time synchronized with internet servers (for initial setup), to generate a unique, time-sensitive code.

      • Verification: When logging in to the application, you enter your username, password, and the current code displayed by the authenticator app. The application verifies the code based on the shared secret and the current time, granting access only if it matches.

    • Benefits of TOTP:

      • Enhanced Security: By adding a layer of time-based verification, TOTP significantly reduces the risk of unauthorized access. Even if your password is compromised, attackers wouldn't have the valid code needed to log in.

      • Offline Functionality: Unlike SMS-based 2FA, TOTP codes are generated on your device, making them usable even without a cellular connection.

      • User-Friendly: TOTP is convenient for users. Once set up, the authenticator app readily displays the required code, streamlining the login process.

      • Cost-Effective: Unlike methods relying on SMS messages, TOTP doesn't incur additional communication charges.

    • TOTP vs. Other 2FA Methods:

      • SMS-based 2FA: While convenient, SMS-based 2FA is less secure as attackers can potentially intercept SMS messages through SIM-swapping techniques.

      • Hardware Tokens: Hardware tokens, like security keys, offer strong security but can be inconvenient to carry around.

    • HOTP vs. TOTP:

      • HOTP: The “H” in HOTP stands for Hash-based Message Authentication Code (HMAC), let's explain more:

      • HMAC: This refers to a specific way of creating a cryptographic hash (a unique string of characters) based on a secret key and some data.

      • One-Time Password (OTP): This is a unique code that's only valid for a single login attempt.

        For more details.

        What’s the Difference Between OTP, TOTP and HOTP?

    • TOTP is a robust and user-friendly 2FA solution that significantly enhances account security without significant drawbacks. By leveraging the shared secret and the current time, TOTP generates unique codes that make unauthorized access incredibly difficult. Integrating TOTP into your application can significantly strengthen your user authentication system.

    • Implementing TOTP 2FA in Ruby on Rails:

      • I am using:

        • Ruby version 3.2.2.

        • Ruby on Rails version 7.1.3.4

        • Users Table for process TOTP.

      • Step 1

          gem 'rotp' # 6.3.0
          gem 'rqrcode' # 2.2.0
        

        Run bundle install to install the gems.

        rotp: This gem offers functionalities for working with TOTP algorithms in Ruby. It provides classes and methods to generate and verify one-time codes.

        rqrcode: This gem to generate QR codes. Users can scan these codes with their authenticator apps to link them to their accounts for 2FA.

      • Step 2

        Add a New Column for OTP Secret: You need to store a secret key for each user, which will be used to generate and verify TOTP codes. Add a new column, let's name it otp_secret to the users table, otp_secret acts as a secret handshake between the user and your application. It's a critical piece of information used to generate unique one-time codes specific to each user.

        •     class AddOtpSecretColumnToUsers < ActiveRecord::Migration[7.1]
                def change
                  add_column :users, :otp_secret, :string
                end
              end
          
  • Step 3

    Implement a setup method to set up TOTP for a user. This involves generating a secret key, creating a TOTP object, and generating a QR code for the user to scan with their TOTP app.

    •     def setup
            otp_secret = ROTP::Base32.random
            totp = ROTP::TOTP.new(otp_secret, issuer: 'TrainingApp')
      
            if current_user.update!(otp_secret: otp_secret)
              qr_code = RQRCode::QRCode.new(totp.provisioning_uri(current_user.email)).as_png(resize_exactly_to: 200)
              render json: { qr_code: Base64.encode64(qr_code.to_s) }
            else
              render json: { error: current_user.errors.full_messages }, status: :unprocessable_entity
            end
          end
      
    • ROTP::Base32.random A secure random number generator produces random bytes, which encoded into a Base32 string, Base32 encoding converts binary data into a human-readable format using 32 ASCII characters, resulting Base32 string can be used as a secret key.

    • ROTP::TOTP.new(otp_secret, issuer: 'TrainingApp') code initializes a new instance and receive otp_secret Base32 encoded secret key for generating the OTP, issuer key an optional parameter that specifies the issuer of the OTP, which is displayed in the user’s authenticator app when they scan the QR code.

    • Update User: current_user.update!(otp_secret: otp_secret) saves the secret key to the user’s record, to be use it when verify the OTP in verify action.

    • RQRCode::QRCode.new(totp.provisioning_uri(current_user.email)).as_png(resize_exactly_to: 200): RQRCode::QRCode creates a QR code that the user can scan to set up TOTP in their app. totp.provisioning_uri(current_user.email) generates a provisioning URI for the TOTP instance, as_png(resize_exactly_to: 200) converts the provisioning URI into a PNG image of a QR code, with resizes the image to 200x200 pixels.

    • Base64.encode64(qr_code.to_s) converted to a Base64 string and returned in the JSON response.

    • Using script in the Postman App to convert the Base64 QR code string in response into QR code Image:

      •           var template = `
                      <img src="data:image/png;base64,{{response.qr_code}}" />
                  `;
        
                  function constructVisualizerPayload() {
                      var res = pm.response.json();
        
                      return {response: res};
                  }
        
                  pm.visualizer.set(template, constructVisualizerPayload());
        
    • Try to Scan the QR code using QR code app not using authenticator app, you will see same like this:

      •     otpauth://totp/TrainingApp:user1%40example.com?secret=LXIL7KO3X2HQAS6RGYW3EKWJVRWMDFO2&issuer=TrainingApp
        
  • Step 4

    • Verifying TOTP action: Implement a method to verify the TOTP code entered by the user

        def verify
          totp = ROTP::TOTP.new(current_user.otp_secret, issuer: 'TrainingApp')
          consumed_timestep = totp.verify(params[:otp_attempt].to_s, drift_behind: 15)
          if consumed_timestep
            current_user.update!(consumed_timestep: consumed_timestep)
            render json: { message: 'Successfully configured OTP protection for your account' }, status: :ok
          else
            render json: { error: 'The code you provided was invalid!' }, status: :unprocessable_entity
          end
        end
      
    • ROTP::TOTP.new(current_user.otp_secret, issuer: 'TrainingApp') initializes a new instance with pass otp_secret that created in the setup action and saved in the user table, issuer key an optional parameter that specifies the issuer of the OTP.

    • The totp.verify method checks the provided OTP against the current OTP generated by the TOTP instance. It compares the user's OTP attempt with the one generated from the secret key and current time. The drift_behind parameter allows the method to accept OTPs from up to 15 second previous time (usually 30 seconds), accommodating slight time differences between the server and the user's device. If the OTP is correct, it returns a timestamp, if not, it returns nil.

    • Update User: If the TOTP code is valid, the user’s record is updated (you might use this to store the last valid timestep or other relevant information).

    • Render Response: Depending on the verification result, an appropriate JSON response is rendered. For more information browser the Rotp Gem.

  • The implementation of TOTP 2FA in application depends heavily on specific requirements and security considerations, factors influencing the implementation include:

    • Authentication Strategy: The existing authentication system will dictate how TOTP integration fits in.

    • User Experience: Balancing security with user convenience is essential. Consider the user flow for enabling, disabling, and using 2FA.

    • Security Best Practices: Proper storage of the OTP secret, handling potential security risks, and adhering to industry standards are crucial.

  1. Summary

    TOTP uses a shared secret key and synchronized clocks on both the user's device and the server to generate unique, time-limited codes. Users typically set this up by scanning a QR code into an authenticator app. While offering enhanced security over SMS-based 2FA by eliminating reliance on cellular networks, TOTP still requires manual code input and is less universally accessible due to smartphone ownership. Secure storage of the shared secret is crucial, as its compromise could lead to account takeover.

  2. References

  3. My articles

10
Subscribe to my newsletter

Read articles from Saleh Alhaddad directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Saleh Alhaddad
Saleh Alhaddad

Seasoned Ruby on Rails Backend Developer with 6 years of experience building scalable web applications. Proficient in crafting robust RESTful APIs, optimizing database performance, and leveraging cloud technologies (AWS, Docker, Kubernetes) to deliver exceptional user experiences. Passionate about Agile development, CI/CD pipelines, and contributing to open-source communities. Let's build amazing software together!