Skip to content

Instantly share code, notes, and snippets.

@pauldougan
Last active April 24, 2024 09:20
Show Gist options
  • Save pauldougan/20f50115ca93b6556c3f75f6c6df1f25 to your computer and use it in GitHub Desktop.
Save pauldougan/20f50115ca93b6556c3f75f6c6df1f25 to your computer and use it in GitHub Desktop.
Generate a Time-based one-time password (TOTP) in TypeScript

Generate a Time-based one-time password (TOTP) in TypeScript

A simple command line example that generates a TOTP code in TypeScript in accordance with IETF rfc6238

Usage

totp.ts

NAME
    totp.ts - generate a TOTP code

SYNOPSIS
    totp.ts SECRET
    
DESCRIPTION
    totp.ts generates a TOTP code using the provided SECRET

EXAMPLES
    totp.ts Y3BUOUHH4CB7JQNQGYRSTUC5PAHYRJAJ

Run locally

git clone https://gist.github.com/20f50115ca93b6556c3f75f6c6df1f25.git
cd 20f50115ca93b6556c3f75f6c6df1f25
npx ts-node ./totp.ts Y3BUOUHH4CB7JQNQGYRSTUC5PAHYRJAJ

Run from the web

npx -p https://gist.github.com/pauldougan/20f50115ca93b6556c3f75f6c6df1f25 ./totp.ts Y3BUOUHH4CB7JQNQGYRSTUC5PAHYRJAJ

{
"name": "totp",
"version": "0.1.0",
"description": "generate a TOTP in typescript",
"main": "./totp.ts",
"dependencies": {
"hi-base32": "^0.5.1"
},
"devDependencies": {
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
},
"scripts": {
"test": "npx ts-node ./totp.ts Y3BUOUHH4CB7JQNQGYRSTUC5PAHYRJAJ"
},
"author": "",
"license": "ISC"
}
#!/usr/bin/env ts-node
import crypto from "node:crypto";
import base32 from "hi-base32";
export function generateToken(secret: string):string {
let counter = Math.floor(Date.now() / 30000);
const decodedSecret = base32.decode.asBytes(secret);
const buffer = Buffer.alloc(8);
for (let i = 0; i < 8; i++) {
buffer[7 - i] = counter & 0xff;
counter = counter >> 8;
}
const hmac = crypto.createHmac("SHA1", Buffer.from(decodedSecret)).update(buffer).digest();
const offset = hmac[hmac.length - 1] & 0xf;
const code =
((hmac[offset] & 0x7f) << 24) |
((hmac[offset + 1] & 0xff) << 16) |
((hmac[offset + 2] & 0xff) << 8) |
(hmac[offset + 3] & 0xff);
return (code % 10 ** 6).toString().padStart(6, "0");
}
let SECRET = process.argv[2];
console.log(generateToken(SECRET));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment