
TOTPの6桁認証コードとは
TOTPの6桁認証コードとは、「時間ベースのワンタイムパスワード(Time-based One-Time Password)」のことで、30秒ごとに変化する6桁の数字のパスコードです。

主に2要素認証(2FA)で使用され、Google AuthenticatorやAuthyなどのアプリで生成されます。
TOTPの6桁認証コードは以下のようなシークレットキーを、もとに生成されます。
5D75PX73V5SMK47PYNG7HLJTHIXL5GJNKXSHZJUK4MU7VTUPFXYZ
Google AuthenticatorやAuthyなどのアプリに登録する場合は、通常はQRコードを読み込んで登録しますが、QRコードにはこのようなシークレットキーのデータが含まれています。
JavaScriptでシークレットキーからTOTPの6桁認証コードを生成
TOTPの6桁認証コードはシークレットキーがあればJavaScriptで処理して生成できます。
やり方はまず、Base32エンコードされたシークレットキーをデコードし、Uint8Arrayとして返すための関数を作成します。
TOTPで使用されるシークレットキーは、通常Base32でエンコードされているため、これをバイト列に変換します。
async function base32Decode(base32) {
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
const cleaned = base32.replace(/=+$/, '').toUpperCase()
const bits = cleaned.split('').map(c => {
const val = alphabet.indexOf(c)
if (val === -1) throw new Error('Invalid base32 char')
return val.toString(2).padStart(5, '0')
}).join('')
const bytes = []
for (let i = 0; i + 8 <= bits.length; i += 8) {
bytes.push(parseInt(bits.slice(i, i + 8), 2))
}
return new Uint8Array(bytes)
}
次にTOTPの6桁コードを生成する関数を作成します。
処理手順
- Base32の秘密鍵をデコード
- 現在時刻を30秒単位で分割(Unix time / 30)
- HMAC-SHA1で署名
- RFC 6238の規定に従って6桁コードを抽出
- 100万で割って6桁にする
async function generateTOTP(secretBase32) {
const secret = await base32Decode(secretBase32)
const timeStep = Math.floor(Date.now() / 1000 / 30)
const buffer = new ArrayBuffer(8)
const view = new DataView(buffer)
view.setUint32(4, timeStep)
const key = await crypto.subtle.importKey(
'raw',
secret,
{ name: 'HMAC', hash: 'SHA-1' },
false,
['sign']
)
const hmac = await crypto.subtle.sign('HMAC', key, buffer)
const hash = new Uint8Array(hmac)
const offset = hash[hash.length - 1] & 0x0f
const binary =
((hash[offset] & 0x7f) << 24) |
((hash[offset + 1] & 0xff) << 16) |
((hash[offset + 2] & 0xff) << 8) |
(hash[offset + 3] & 0xff)
return (binary % 1000000).toString().padStart(6, '0')
}
試しにブラウザのConsoleで以下のコードを実行すると、シークレットキーから6桁の認証コードが生成されることが確認できます。
async function base32Decode(base32) {
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
const cleaned = base32.replace(/=+$/, '').toUpperCase()
const bits = cleaned.split('').map(c => {
const val = alphabet.indexOf(c)
if (val === -1) throw new Error('Invalid base32 char')
return val.toString(2).padStart(5, '0')
}).join('')
const bytes = []
for (let i = 0; i + 8 <= bits.length; i += 8) {
bytes.push(parseInt(bits.slice(i, i + 8), 2))
}
return new Uint8Array(bytes)
}
async function generateTOTP(secretBase32) {
const secret = await base32Decode(secretBase32)
const timeStep = Math.floor(Date.now() / 1000 / 30)
const buffer = new ArrayBuffer(8)
const view = new DataView(buffer)
view.setUint32(4, timeStep)
const key = await crypto.subtle.importKey(
'raw',
secret,
{ name: 'HMAC', hash: 'SHA-1' },
false,
['sign']
)
const hmac = await crypto.subtle.sign('HMAC', key, buffer)
const hash = new Uint8Array(hmac)
const offset = hash[hash.length - 1] & 0x0f
const binary =
((hash[offset] & 0x7f) << 24) |
((hash[offset + 1] & 0xff) << 16) |
((hash[offset + 2] & 0xff) << 8) |
(hash[offset + 3] & 0xff)
return (binary % 1000000).toString().padStart(6, '0')
}
const secretKey = prompt('シークレットキーを入力', '5D75PX73V5SMK47PYNG7HLJTHIXL5GJNKXSHZJUK4MU7VTUPFXYZ')
generateTOTP(secretKey).then((code) => {
console.log('認証コード:', code)
})

シークレットキーはあるが、Google Authenticatorなどをパソコンにインストールできない状況でも、この方法であればアプリなしで6桁の認証コードを生成できます。
TOTPの6桁認証コードを生成するWebページを作成
前述のコードの処理をsetIntervalで30秒ごとに実行するようにすれば、シークレットキーからTOTPの6桁認証コードを生成するWebページを作成できます。
実際に作成したサンプルは以下のリンクから確認できます。