Implementing Two-Factor Authentication (2FA) with TOTP in Golang

Kittipat.Po
4 min readJul 22, 2023

Introduction

In an era of increasing online security concerns, implementing robust authentication mechanisms is crucial. Two-Factor Authentication (2FA) provides an additional layer of security by requiring users to provide a second form of verification, typically a time-based one-time password (TOTP) or a HMAC-based one-time password (HOTP). In this blog post, we will explore how TOTP work and walk you through implementing 2FA using Golang.

https://www.twilio.com/docs/glossary/totp

TOTP (Time-Based One-Time Password)

Think of TOTP as a time-limited password that keeps changing every few seconds. When you set up 2FA on an application, it generates a secret key that is securely shared between the application and your device. Your device uses this key, combined with the current time, to generate a unique password that remains valid for a short period, typically 30 seconds. This password is entered along with your regular username and password to complete the login process. Popular applications like Google Authenticator use TOTP.

Implementing 2FA with TOTP in Golang:

To implement 2FA with TOTP in Golang, we will use the github.com/xlzd/gotp library, which simplifies the process. Let's break down the steps:

https://www.descope.com/learn/post/totp
  • Generating a new TOTP key
    When you enable 2FA on an application, it generates a secret key. This key is shared securely between the application and your device.
  • Generating a TOTP code:
    To generate a TOTP code, your device combines the shared key with the current time and generates a unique password. This password remains valid for a short period, usually 30 seconds.
  • Validating a TOTP code:
    When you log in using 2FA, the application expects you to enter the correct TOTP code. The server uses the same shared key and checks if the code you provided matches the one generated on the server-side. If they match, you are granted access.

To better understand the process, let’s go through a practical example with Golang

Generating a new TOTP key and QR code

When you enable 2FA on an application, it generates a secret key. Instead of manually sharing this key, you can generate a QR code containing the key. This QR code is then scanned by the user’s device to securely import the secret key. Here's an example code snippet:

package main

import (
"fmt"
"time"

"os"

"github.com/mdp/qrterminal/v3"
"github.com/skip2/go-qrcode"
"github.com/xlzd/gotp"
)

func main() {
randomSecret := gotp.RandomSecret(16)
fmt.Println("Random secret:", randomSecret)
generateTOTPWithSecret(randomSecret)
}

func generateTOTPWithSecret(randomSecret string) {
totp := gotp.NewDefaultTOTP(randomSecret)
fmt.Println("Current one-time password is:", totp.Now())

uri := totp.ProvisioningUri("user@email.com", "myApp")
fmt.Println("Secret Key URI:", uri)

qrcode.WriteFile(uri, qrcode.Medium, 256, "qr.png")

// Generate and display QR code in the terminal
qrterminal.GenerateWithConfig(uri, qrterminal.Config{
Level: qrterminal.L,
Writer: os.Stdout,
BlackChar: qrterminal.BLACK,
WhiteChar: qrterminal.WHITE,
})

fmt.Println("\nScan the QR code with your authenticator app")
}

Output

By generating QR codes directly from the Google Authenticator Key URI Format, such as

otpauth://totp/myApp:user@email.com?issuer=myApp&secret=5N2FFQVLYJMGEZIACGQDISVONA

Users can effortlessly set up 2FA by scanning this QR code, minimizing errors and ensuring a smooth authentication process. For a detailed reference on the Google Authenticator URI format, you can visit the Google Authenticator Key URI Format.

Interactive 2FA Setup: QR Code Scanning and OTP Verification in Golang

To further enhance the user experience in your Golang-based Two-Factor Authentication (2FA) implementation, we’ll provide an example code that generates a QR code, allows users to scan it with their authenticator app, and then waits for the user to input the One-Time Password (OTP) for validation.

package main

import (
"bufio"
"fmt"
"os"
"time"

"github.com/mdp/qrterminal"
"github.com/skip2/go-qrcode"
"github.com/xlzd/gotp"
)

func main() {
randomSecret := gotp.RandomSecret(16)
fmt.Println("Random secret:", randomSecret)
generateTOTPWithSecret(randomSecret)
verifyOTP(randomSecret)
}

func generateTOTPWithSecret(randomSecret string) {
uri := gotp.NewDefaultTOTP(randomSecret).ProvisioningUri("user@email.com", "myApp")
fmt.Println("Secret Key URI:", uri)

qrcode.WriteFile(uri, qrcode.Medium, 256, "qr.png")

// Generate and display QR code in the terminal
qrterminal.GenerateWithConfig(uri, qrterminal.Config{
Level: qrterminal.L,
Writer: os.Stdout,
BlackChar: qrterminal.BLACK,
WhiteChar: qrterminal.WHITE,
})

fmt.Println("\nScan the QR code with your authenticator app")
}

func verifyOTP(randomSecret string) {
totp := gotp.NewDefaultTOTP(randomSecret)

// Wait for user input of the OTP
fmt.Print("Enter the OTP from your authenticator app: ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
userInput := scanner.Text()

// Validate the provided OTP
if totp.Verify(userInput, time.Now().Unix()) {
fmt.Println("Authentication successful! Access granted.")
} else {
fmt.Println("Authentication failed! Invalid OTP.")
}
}

In the presented code, we initiate the process by generating a random secret key. The subsequent steps involve the dynamic creation of a Time-Based One-Time Password (TOTP) and the generation of a QR code provisioning URI. This URI, easily interpretable by mobile authenticator apps such as Google Authenticator, simplifies the setup of Two-Factor Authentication (2FA).

The verifyOTP function demonstrates the validation of the TOTP with the current time, ensuring secure and timely authentication. Execute this code to experience the dynamic TOTP generation, providing an additional layer of security for your Golang application.

Conclusion

Implementing Two-Factor Authentication (2FA) adds an extra layer of security to your applications. In this blog post, we explored how TOTP work and provided non-technical explanations to help you understand the concepts. We also provided example code and walked you through implementing 2FA using Golang, using the github.com/xlzd/gotp library.

--

--