Oh MyUtils

TOTP Generator - Time-Based One-Time Password Tool Online

Generate and verify TOTP codes for 2FA testing. Create secrets, QR codes, and otpauth:// URIs. RFC 6238 compliant — 100% client-side, secret keys never leave your browser.

100% Client-Side — Secret keys never leave your browser
Algorithm
Digits
Period (seconds)

Enter a secret key to generate TOTP codes

Frequently Asked Questions

What is a TOTP Generator?

A TOTP (Time-based One-Time Password) Generator is an online tool that creates time-limited authentication codes following the RFC 6238 standard. TOTP is the algorithm behind popular authenticator apps like Google Authenticator, Authy, and Microsoft Authenticator. It works by combining a shared secret key with the current Unix timestamp using an HMAC (Hash-based Message Authentication Code) function, then truncating the result to produce a short numeric code (typically 6 or 8 digits). The code changes every 30 seconds (by default), making it useful as a second factor in two-factor authentication (2FA). This tool allows developers to generate, verify, and test TOTP codes directly in the browser without installing an authenticator app.

How do I use this tool?

1. Enter a Base32-encoded secret key, or click "Generate Secret" to create a random one. 2. Configure the TOTP parameters: algorithm (SHA-1 is the default used by most services), digit count (6 or 8), and time period (30 seconds is standard). 3. The tool immediately displays the current TOTP code with a countdown timer showing when it will refresh. 4. Optionally, fill in the Issuer and Label fields to generate a complete otpauth:// URI. 5. Scan the generated QR code with your authenticator app to verify the codes match. 6. Use the Verify tab to paste a code and check if it is valid for the configured secret and time window. 7. Click the copy button next to any code or URI to copy it to your clipboard.

Is my secret key safe? Does it get sent to a server?

Your secret key is 100% safe and never leaves your browser. All TOTP computation -- HMAC calculation, code generation, verification, and QR code rendering -- is performed entirely client-side using JavaScript. The tool uses the otpauth library for RFC 6238 computation and the browser's native Web Crypto API for cryptographic operations. No data is transmitted to any server, no analytics track your secret key content, and no data is stored anywhere beyond your browser tab's memory. This makes the tool safe for testing with real TOTP secrets during development and QA.

What is the otpauth:// URI format?

The otpauth:// URI is a standardized format for provisioning TOTP (and HOTP) secrets into authenticator apps. When encoded into a QR code, scanning it automatically configures the authenticator app with all necessary parameters. The format is: otpauth://totp/{label}?secret={secret}&issuer={issuer}&algorithm={algorithm}&digits={digits}&period={period}. The label is typically formatted as issuer:account (e.g., MyApp:user@example.com), the secret is the shared key encoded in Base32, and optional parameters include algorithm (SHA1, SHA256, SHA512), digits (6 or 8), and period (defaults to 30 seconds). This format is supported by Google Authenticator, Microsoft Authenticator, Authy, FreeOTP, and virtually all standards-compliant authenticator apps.

What is the difference between TOTP and HOTP?

TOTP (Time-based One-Time Password, RFC 6238) generates codes based on the current time. The code changes automatically every N seconds (default 30), and both the server and client use the current Unix timestamp as the counter, so they stay synchronized as long as their clocks are reasonably accurate. HOTP (HMAC-based One-Time Password, RFC 4226) generates codes based on an incrementing counter. Each time a code is generated, the counter advances by one, and the server and client must track the counter independently -- desynchronization can occur if codes are generated but not used. TOTP is technically an extension of HOTP where the "counter" is derived from the current time divided by the period. This tool focuses on TOTP as it is the dominant standard for modern 2FA implementations.

Why are my TOTP codes different from my authenticator app?

If the codes generated by this tool don't match your authenticator app, check these common causes: (1) Wrong secret key -- ensure the Base32 secret is entered exactly, as even one wrong character will produce completely different codes. (2) Algorithm mismatch -- most services use SHA-1 (the default), so make sure both the tool and your app are configured identically if your service uses SHA-256 or SHA-512. (3) Digit count mismatch -- most services use 6 digits, but some enterprise tools use 8 digits. (4) Period mismatch -- the standard period is 30 seconds, but some services use 60 or 90 seconds. (5) Clock skew -- TOTP is time-sensitive, so if your device clock is significantly off (more than 30 seconds), codes will not match. Ensure your system clock is synchronized via NTP.

How secure is TOTP for two-factor authentication?

TOTP provides a strong second factor for authentication when implemented correctly. Each code is valid for only one time period (typically 30 seconds), limiting the window for interception attacks. It uses cryptographic hash functions (SHA-1, SHA-256, or SHA-512) to derive codes from the secret key via HMAC, making it computationally infeasible to reverse-engineer the secret from observed codes. The shared secret is established once during enrollment and never transmitted again during normal authentication. However, TOTP is not immune to all attacks -- phishing attacks can capture and replay codes in real-time, and the shared secret can be compromised if the server's secret storage is breached. For the highest security, combine TOTP with phishing-resistant methods like WebAuthn/FIDO2.

Code Examples

// TOTP Generator using Web Crypto API (RFC 6238)

function base32Decode(base32) {
  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
  const cleaned = base32.toUpperCase().replace(/[^A-Z2-7]/g, '');
  let bits = '';
  for (const char of cleaned) {
    const val = alphabet.indexOf(char);
    if (val === -1) throw new Error(`Invalid Base32 character: ${char}`);
    bits += val.toString(2).padStart(5, '0');
  }
  const bytes = new Uint8Array(Math.floor(bits.length / 8));
  for (let i = 0; i < bytes.length; i++) {
    bytes[i] = parseInt(bits.substr(i * 8, 8), 2);
  }
  return bytes;
}

async function generateTOTP(secret, options = {}) {
  const {
    algorithm = 'SHA-1',
    digits = 6,
    period = 30,
    timestamp = Date.now(),
  } = options;

  const counter = Math.floor(timestamp / 1000 / period);
  const counterBuffer = new ArrayBuffer(8);
  const counterView = new DataView(counterBuffer);
  counterView.setUint32(4, counter, false);

  const keyBytes = base32Decode(secret);
  const cryptoKey = await crypto.subtle.importKey(
    'raw', keyBytes,
    { name: 'HMAC', hash: algorithm },
    false, ['sign']
  );

  const hmacBuffer = await crypto.subtle.sign('HMAC', cryptoKey, counterBuffer);
  const hmac = new Uint8Array(hmacBuffer);

  const offset = hmac[hmac.length - 1] & 0x0f;
  const code =
    ((hmac[offset] & 0x7f) << 24) |
    ((hmac[offset + 1] & 0xff) << 16) |
    ((hmac[offset + 2] & 0xff) << 8) |
    (hmac[offset + 3] & 0xff);

  const otp = code % Math.pow(10, digits);
  return otp.toString().padStart(digits, '0');
}

function generateSecret(bits = 160) {
  const bytes = new Uint8Array(bits / 8);
  crypto.getRandomValues(bytes);
  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
  let result = '', buffer = 0, bufferLength = 0;
  for (const byte of bytes) {
    buffer = (buffer << 8) | byte;
    bufferLength += 8;
    while (bufferLength >= 5) {
      bufferLength -= 5;
      result += alphabet[(buffer >> bufferLength) & 0x1f];
    }
  }
  if (bufferLength > 0) {
    result += alphabet[(buffer << (5 - bufferLength)) & 0x1f];
  }
  return result;
}

// Usage:
// const secret = generateSecret();
// const code = await generateTOTP(secret);
// console.log('TOTP:', code);

Related Tools