DEV Community

Cover image for Google Authenticator integration with Spring Boot
Sahil Khurana
Sahil Khurana

Posted on • Originally published at innostax.com

Google Authenticator integration with Spring Boot

Google Authenticator Integration with Spring Boot

Passwords alone just don't cut it anymore. We've all seen the headlines — data breaches, credential stuffing, account takeovers. And yet, a shocking number of applications still rely on a single password as the only line of defense. If you're building something with Spring Boot and haven't wired up multi-factor authentication yet, this guide is for you.

We'll walk through integrating Google Authenticator into a Spring Boot project — step by step, with real code. By the end, your users will need both their password and a time-sensitive code from their phone to get in. That's a meaningful security upgrade.


What Exactly Is MFA — and Why Should You Care?

Multi-factor authentication (MFA) — sometimes called two-factor authentication or 2FA — is the practice of requiring more than one proof of identity before granting access. Instead of just "something you know" (your password), you add "something you have" (your phone) or "something you are" (a fingerprint).

It sounds simple, but the impact is significant. Even if an attacker manages to steal or guess a user's password, they still can't log in without that second factor. For industries where data sensitivity is high — think fintech, healthcare, legal — MFA isn't optional, it's expected.


How Does a TOTP-Based Factor Actually Work?

Google Authenticator generates what's called a Time-based One-Time Password (TOTP). Here's the basic idea:

When a user first enables 2FA, the server creates a shared secret key and hands it to the user (usually via a QR code). From that point on, both the server and the app on the user's phone use the same algorithm — combining that secret with the current timestamp — to independently calculate a 6-digit code. The codes are valid for only 30 seconds.

When the user logs in, they open Google Authenticator, read the current code, and type it in. The server runs the same calculation and checks if the numbers match. No network call required on the app's side, no SMS that could be intercepted. It's elegant and robust.


What Makes Google Authenticator a Good Choice?

There are several authenticator apps out there, but Google Authenticator remains a go-to for good reasons:

  • It works completely offline — no cell signal or Wi-Fi needed once set up
  • It's immune to SIM swap attacks, which plague SMS-based 2FA
  • Setup is as easy as scanning a QR code
  • It's free, widely trusted, and available on both iOS and Android

Integrating Google Authenticator into a Spring Boot Project

Let's get into the actual implementation. There are four steps: add the right dependencies, generate a secret key per user, produce a QR code for setup, and verify the TOTP code at login time.

Step 1 — Add the Required Dependencies

Open your pom.xml and add the following:

<dependency>
    <groupId>de.taimos</groupId>
    <artifactId>totp</artifactId>
    <version>1.0</version>
</dependency>

<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.0</version>
    <scope>compile</scope>
</dependency>

<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.3.0</version>
    <scope>compile</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode

The totp library handles the TOTP math. The two zxing libraries handle QR code generation — they're from Google and do a solid job.


Step 2 — Generate a Secret Key for Each User

Every user gets their own unique secret key. This is generated once during setup and stored (securely) in your database alongside their account.

public static String generateSecretKey() {
    SecureRandom random = new SecureRandom();
    byte[] bytes = new byte[20];
    random.nextBytes(bytes);
    Base32 base32 = new Base32();
    return base32.encodeToString(bytes);
}
Enter fullscreen mode Exit fullscreen mode

SecureRandom ensures the key is cryptographically random. The result is a Base32-encoded string — that format is what TOTP libraries and authenticator apps expect.


Step 3 — Generate the QR Code for Setup

Once you have the secret key, you need to present it to the user in a way Google Authenticator can consume. That means building a specially formatted otpauth:// URI and then encoding it as a QR code image.

private static final String ENCODED_SPACE = "%20";
private static final String PLUS_SYMBOL = "+";

public static String generateAuthenticatorQR(String email, String secretKey, String accountName) {
    try {
        String barCodeUrl = getGoogleAuthenticatorBarCode(secretKey, email, accountName);
        return createQRCode(barCodeUrl);
    } catch (Exception e) {
        System.out.println("Error generating QR code: " + e.getMessage());
    }
    return null;
}

private static String getGoogleAuthenticatorBarCode(String secretKey, String account, String issuer) {
    try {
        String utf8 = "UTF-8";
        return "otpauth://totp/"
            + URLEncoder.encode(issuer + ":" + account, utf8).replace(PLUS_SYMBOL, ENCODED_SPACE)
            + "?secret=" + URLEncoder.encode(secretKey, utf8).replace(PLUS_SYMBOL, ENCODED_SPACE)
            + "&issuer=" + URLEncoder.encode(issuer, utf8).replace(PLUS_SYMBOL, ENCODED_SPACE);
    } catch (UnsupportedEncodingException e) {
        throw new IllegalStateException(e);
    }
}

public static String createQRCode(String barCodeData) {
    try {
        String filePath = "QRCode.png";
        int size = 400;
        BitMatrix matrix = new MultiFormatWriter().encode(barCodeData, BarcodeFormat.QR_CODE, size, size);
        FileOutputStream out = new FileOutputStream(filePath);
        MatrixToImageWriter.writeToStream(matrix, "png", out);
        File img = new File(filePath);
        byte[] imgBytes = FileUtils.readFileToByteArray(img);
        return "data:image/PNG;base64," + Base64.getEncoder().encodeToString(imgBytes);
    } catch (Exception e) {
        System.out.println("Error creating QR code: " + e.getMessage());
    }
    return "Failed to generate QR";
}
Enter fullscreen mode Exit fullscreen mode

The method returns a Base64-encoded PNG image that you can drop directly into an <img> tag on your setup page. The user scans it with Google Authenticator, and they're enrolled.


Step 4 — Verify the TOTP at Login

When a user logs in and submits their 6-digit code, you need to verify it against the secret key stored for their account:

public static String getTOTPCode(String secretKey) {
    Base32 base32 = new Base32();
    byte[] bytes = base32.decode(secretKey);
    String hexKey = Hex.encodeHexString(bytes);
    return TOTP.getOTP(hexKey);
}
Enter fullscreen mode Exit fullscreen mode

Call this method with the user's stored secret key, get the expected code back, and compare it to what they entered. If it matches — they're in. If not — reject the attempt.


A Few Things Worth Keeping in Mind

Before you ship this, a couple of practical notes:

Store secret keys securely. Treat them like passwords — encrypt them at rest. If an attacker gets your database and the keys are in plaintext, the 2FA protection is gone.

Handle clock drift. TOTP codes are time-based, so if a user's phone clock is significantly off, valid codes might get rejected. Most TOTP libraries have a tolerance window — usually ±1 interval — to accommodate minor drift. Make sure yours is configured reasonably.

Give users a recovery path. What happens if someone loses their phone? You'll want backup codes or an admin-assisted recovery flow before you mandate 2FA for all users.


Wrapping Up

Adding Google Authenticator to a Spring Boot app is genuinely not that complex — a couple of libraries, some key generation logic, a QR code at setup, and a verification check at login. The lift is small; the security payoff is real.

For any application handling sensitive user data, this kind of layered authentication is increasingly table stakes. Whether you're building for finance, healthcare, or just want to protect your users properly, getting MFA in place early saves a lot of headache down the road.

Have questions or running into something unexpected during setup? Drop a comment or reach out — happy to help troubleshoot.


Building secure authentication systems and need a team that understands backend security beyond just checking compliance boxes? At Innostax, we help companies implement MFA, strengthen authentication flows, and build secure Spring Boot applications that hold up in real-world production environments. Learn more at innostax.com or get in touch at innostax.com/contact.

Originally published on the Innostax Engineering Blog.

Top comments (0)