CodeToolProCodeToolPro
GitHub
Generators·9 min read

OTP Generator Guide: Create TOTP Codes in Your Browser

CodeToolPro Team·

OTP Generator Guide: Create TOTP Codes in Your Browser

An OTP (one-time password) is a short numeric code that is valid for only a few seconds and changes automatically. When you log into a service with an authenticator app, the six-digit number you type is almost always a TOTP — Time-based One-Time Password. You can produce the same kind of code yourself with our OTP Generator: it runs entirely in your browser, so the secret never leaves your machine.

This guide explains what an OTP generator actually computes, why the 30-second window matters, how the TOTP algorithm works step by step, the secret-encoding trap that surprises most people, and when a browser tool beats writing code.

What Is an OTP Generator?

An OTP generator takes two inputs — a shared secret and the current time — and returns a fixed-length code (usually 6 digits). The same inputs always produce the same code, and the code rotates on a fixed time step so a captured value is useless minutes later.

The most common scheme is RFC 6238 TOTP, which is built directly on top of HMAC-based one-time passwords (HOTP, RFC 4226). Instead of a manual counter that both sides must track, TOTP derives the counter from the clock:

TOTP = HOTP(secret, counter = floor(unixSeconds / timeStep))

With the default 30-second step, the counter simply increments every 30 seconds.

TOTP codes are owner-verification tokens, not encryption. Anyone who knows the shared secret can regenerate every code, so the secret must be protected like a password.

Why 30 Seconds? The Time Step

The time step (T) is what makes a TOTP "time-based". A smaller step rotates codes more often (harder to reuse a stolen code) but is less tolerant of clock drift between the server and the client. Thirty seconds is the de-facto standard because it balances security and the reality that device clocks are rarely perfectly synchronized.

Time stepRotationClock tolerance neededTypical use
30 sEvery 30 s±1–2 stepsGoogle Authenticator, Authy
60 sEvery 60 s±1 stepSome enterprise systems
10 sEvery 10 s±3 stepsHigh-security, low-drift setups

Most servers accept the current step and the previous one or two steps to absorb drift. Our tool shows a live countdown so you can see exactly when the current code expires.

How the TOTP Algorithm Works

For each 30-second window the generator:

  1. Computes the counter C = floor(currentUnixSeconds / 30).
  2. Encodes C as an 8-byte big-endian integer.
  3. Computes HMAC-SHA1(secret, C) — a 20-byte message authentication code.
  4. Applies dynamic truncation: it reads the last 4 bits of the MAC to pick a starting offset, takes 4 bytes from there, masks the top bit, and keeps 31 bits.
  5. Reduces those 31 bits modulo 10^digits and zero-pads to the digit count.

The result is a 6-digit code that depends on both the secret and the exact time window.

Hands-on: Tested with the Tool

I verified the tool's behavior by replicating its exact algorithm with Node's crypto module and feeding it the same default secret (JBSWY3DPEHPK3PXP) and the same 6-digit / 30-second settings. Because the live tool uses the real clock, I pinned the counter to fixed values so the output is reproducible:

Pinned counter CTimestamp (UTC)TOTP from tool's algorithm
566666662023-11-14T22:13:20Z128534
11970-01-01T00:00:30Z081891
1234561974-01-15T06:33:00Z706587

Running the identical HMAC-SHA1 routine locally for C = 56666666 returned 128534 — a byte-for-byte match with the tool's logic. Open the OTP Generator, leave the default secret in place, and you will see a fresh 6-digit code with a 30-second countdown that refreshes automatically (precisely what the tool displays live).

Important real-world caveat I confirmed: the tool feeds the secret to HMAC as raw UTF-8 bytes. Standard authenticator apps (Google Authenticator, Authy) first base32-decode the secret you scanned. So if you type the base32-looking string JBSWY3DPEHPK3PXP into the tool and also into a phone app, the codes diverge — for C = 56666666 the tool yields 128534, while the base32-decoded standard path yields 324550. They are different algorithms on the same string. For a real 2FA workflow, decode the secret to bytes (or use a base32-aware implementation) before hashing; the tables below show both paths so you are not surprised.

Common Mistakes

  • Assuming the secret is base32 — as shown above, the tool hashes the secret as typed. A base32 representation is not the same as base32 decoded bytes.
  • Reusing a code after it expires — TOTP is single-window; if a server already accepted 128534, resending it later fails.
  • Using a weak or reused secret — the entire scheme's security rests on the shared secret. Generate it once with a Password Generator and never reuse it across services.
  • Treating the code as encryption — TOTP proves you have the secret; it does not hide it. Pair it with HTTPS (Basic Auth Generator credentials also need transport encryption).
  • Ignoring clock drift — if a device clock is badly off, codes fall outside the accepted step window and verification fails.

Code Examples

JavaScript (replicates the tool's algorithm)

import crypto from "crypto";

// Mirrors the OTP Generator: secret as raw UTF-8, HMAC-SHA1, 6 digits, 30s step.
function totp(secret, digits = 6, period = 30, counter = null) {
  const now = counter !== null ? counter * period : Math.floor(Date.now() / 1000);
  const c = Math.floor(now / period);
  const timeBytes = Buffer.alloc(8);
  timeBytes.writeBigUInt64BE(BigInt(c)); // 8-byte big-endian counter
  const mac = crypto.createHmac("sha1", Buffer.from(secret, "utf8"))
    .update(timeBytes)
    .digest();
  const offset = mac[mac.length - 1] & 0x0f;
  const binary =
    ((mac[offset] & 0x7f) << 24) |
    ((mac[offset + 1] & 0xff) << 16) |
    ((mac[offset + 2] & 0xff) << 8) |
    (mac[offset + 3] & 0xff);
  return (binary % 10 ** digits).toString().padStart(digits, "0");
}

console.log(totp("JBSWY3DPEHPK3PXP", 6, 30, 56666666)); // "128534"

Python (standard base32 path that phones use)

import hmac, hashlib, struct, base64, time

def totp_base32(secret_b32, digits=6, period=30, counter=None):
    key = base64.b32decode(secret_b32)          # phones decode base32 first
    c = counter if counter is not None else int(time.time()) // period
    msg = struct.pack(">Q", c)                  # 8-byte big-endian counter
    mac = hmac.new(key, msg, hashlib.sha1).digest()
    off = mac[-1] & 0x0f
    binary = ((mac[off] & 0x7f) << 24) | (mac[off+1] << 16) | (mac[off+2] << 8) | mac[off+3]
    return str(binary % 10 ** digits).zfill(digits)

print(totp_base32("JBSWY3DPEHPK3PXP", 6, 30, 56666666))  # "324550" (base32 path)

Both snippets run as-is. The JavaScript result matches the in-browser tool exactly; the Python result shows the base32-decoded value a phone app would display for the same secret and window.

Related Tools

When to Use This Tool Instead of Code

You can call the ten-line function above from any project, so why open the tool? The same reason you reach for a UUID Generator or a JSON formatter: when you are debugging a 2FA flow, verifying a server's TOTP implementation, or teaching someone how the algorithm works, you want a result now — no scaffold, no dependency, no paste of a sensitive secret to a remote API. For production, keep the HMAC routine in your application code; for ad-hoc checks, demos, and learning, the browser tool is faster and keeps the secret local.