Vanilla JavaScript Projects

Project 31, Security and auth

TOTP 2FA Authenticator

The six digit codes from authenticator apps are just math on a shared secret and the clock. This page does that math, live, for as many accounts as you like.

482 913
Algorithm
TOTP, RFC 6238
Hash
HMAC-SHA1 via Web Crypto
Dependencies
QR generator only
Your browser
Checking

Your codes

Click a code to copy it. Codes change every 30 seconds.

    Add an account

    Make a new secret

    Verify a code

    Checks the code for the first account, allowing one step of clock drift.

    How it works

    1. Count time stepsThe current Unix time is divided by 30 to get a counter that changes every 30 seconds.
    2. Sign the counterThe counter, as 8 bytes, is signed with HMAC SHA-1 using the account's secret as the key.
    3. TruncateFour bytes are picked from the signature using its last nibble, turned into a number, and cut to 6 digits.
    async function totp(base32Secret, step = 30, digits = 6) {
      const counter = Math.floor(Date.now() / 1000 / step);
      const msg = new DataView(new ArrayBuffer(8));
      msg.setUint32(4, counter);                              // 8 byte big-endian counter
      const key = await crypto.subtle.importKey("raw", base32Decode(base32Secret),
        { name: "HMAC", hash: "SHA-1" }, false, ["sign"]);
      const h = new Uint8Array(await crypto.subtle.sign("HMAC", key, msg.buffer));
      const o = h[19] & 0xf;                                  // dynamic truncation
      const n = ((h[o] & 0x7f) << 24) | (h[o + 1] << 16) | (h[o + 2] << 8) | h[o + 3];
      return String(n % 10 ** digits).padStart(digits, "0");
    }