
oath-toolkit で CLI から OTP を取得する - 自動化時代の2FA対応
作成日:
更新日:
なぜ CLI で OTP が必要なのか
最近、AI エージェントでのブラウザ操作や Playwright でのテスト自動化など、プログラムからブラウザを操作する機会が増えてきました。
これらの自動化で厄介なのが2要素認証(2FA)のログイン処理です。Google Authenticator などのスマホアプリを毎回手動で確認するのは、せっかくの自動化が台無しです。
oath-toolkit を使えば、ターミナルから OTP を取得できるため:
- Playwright / Puppeteer のE2Eテストで2FAログインを自動化
- Cursor / Claude などのAIエージェントがブラウザ操作する際の認証
- CI/CD パイプラインでのセキュアな自動デプロイ
- 単純にターミナルから離れずにOTPを取得したい
といったユースケースに対応できます。
oath-toolkit とは
oath-toolkit は、OATH(Initiative for Open Authentication)標準に準拠した OTP 生成ツールです。TOTP(時間ベース)と HOTP(カウンタベース)の両方に対応しています。
インストール
macOS(Homebrew)
brew install oath-toolkit
Ubuntu / Debian
sudo apt update
sudo apt install oathtool
RHEL / CentOS / Fedora
# RHEL/CentOS 8以降、Fedora
sudo dnf install oathtool
# CentOS 7以前
sudo yum install oathtool
インストール確認
oathtool --version
シークレットキーの取得
Google Authenticator に登録する際に表示されるシークレットキー(Base32形式の文字列)が必要です。
| 状況 | 対応方法 |
|---|---|
| 新規登録時 | QRコードの下に表示される「セットアップキー」や「シークレットキー」をメモしておく |
| 既存のアカウント | サービス側で2FAを一度解除し、再設定する際にシークレットキーを控える |
⚠️ 注意: Google Authenticator アプリからシークレットキーを直接取り出すことはできません。新規登録時に必ずメモしておきましょう。
基本的な使い方
OTP を生成
# TOTP(時間ベースのOTP)を生成
oathtool --totp --base32 "YOUR_SECRET_KEY"
実行例
# 例: シークレットキーが "JBSWY3DPEHPK3PXP" の場合
$ oathtool --totp --base32 "JBSWY3DPEHPK3PXP"
123456
クリップボードにコピー
# macOS
oathtool --totp --base32 "YOUR_SECRET_KEY" | pbcopy
# Linux(xclipを使用)
oathtool --totp --base32 "YOUR_SECRET_KEY" | xclip -selection clipboard
便利なシェル設定
エイリアスを設定
~/.zshrc に追加:
# 特定サービス用のOTP取得エイリアス
alias otp-github='oathtool --totp --base32 "YOUR_GITHUB_SECRET"'
alias otp-aws='oathtool --totp --base32 "YOUR_AWS_SECRET"'
# クリップボードにコピーするバージョン(macOS)
alias otpc-github='oathtool --totp --base32 "YOUR_GITHUB_SECRET" | pbcopy && echo "Copied!"'
シークレットファイルで複数サービスを管理
より実用的な方法として、シークレットファイルとシェル関数を組み合わせます。
1. シークレットファイルを作成
# ~/.otp_secrets ファイルを作成(パーミッションを制限)
touch ~/.otp_secrets
chmod 600 ~/.otp_secrets
2. サービスを登録
github:JBSWY3DPEHPK3PXP
aws:ANOTHERSECRETKEY
sakura-vps:SECRETKEYHERE
3. シェル関数を定義
~/.zshrc に追加:
# OTP取得関数
otp() {
local secrets_file="$HOME/.otp_secrets"
if [[ -z "$1" ]]; then
echo "Usage: otp <service_name>"
echo "Available services:"
cut -d: -f1 "$secrets_file" | sed 's/^/ - /'
return 1
fi
local secret=$(grep "^$1:" "$secrets_file" | cut -d: -f2)
if [[ -z "$secret" ]]; then
echo "Service '$1' not found"
return 1
fi
local code=$(oathtool --totp --base32 "$secret")
# クリップボードにコピー(OS判定)
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "$code" | pbcopy
elif command -v xclip &> /dev/null; then
echo "$code" | xclip -selection clipboard
fi
echo "OTP: $code (copied to clipboard)"
}
# 補完設定
_otp_completion() {
local secrets_file="$HOME/.otp_secrets"
if [[ -f "$secrets_file" ]]; then
compadd $(cut -d: -f1 "$secrets_file")
fi
}
compdef _otp_completion otp
使用例
# 利用可能なサービス一覧を表示
$ otp
Usage: otp <service_name>
Available services:
- github
- aws
- sakura-vps
# GitHubのOTPを取得(自動でクリップボードにコピー)
$ otp github
OTP: 123456 (copied to clipboard)
Playwright での活用例
E2E テストで 2FA ログインを自動化する例:
import { test, expect } from '@playwright/test';
import { execSync } from 'child_process';
// OTPを取得するヘルパー関数
function getOTP(service: string): string {
const secretsFile = `${process.env.HOME}/.otp_secrets`;
const secret = execSync(`grep "^${service}:" ${secretsFile} | cut -d: -f2`)
.toString()
.trim();
return execSync(`oathtool --totp --base32 "${secret}"`)
.toString()
.trim();
}
test('2FA login', async ({ page }) => {
await page.goto('https://example.com/login');
// 通常のログイン
await page.fill('[name="email"]', 'user@example.com');
await page.fill('[name="password"]', 'your-password');
await page.click('button[type="submit"]');
// 2FAページでOTPを入力
await page.waitForSelector('[name="otp"]');
const otp = getOTP('example-service');
await page.fill('[name="otp"]', otp);
await page.click('button[type="submit"]');
// ログイン成功を確認
await expect(page).toHaveURL('/dashboard');
});
セキュリティ上の注意
| 項目 | 説明 |
|---|---|
| シークレットキーの保護 | シークレットキーがあれば誰でもOTPを生成できる。絶対に他人に見せない |
| ファイルパーミッション | chmod 600 で自分だけ読み書き可能に設定 |
| Git管理しない | .gitignore にシークレットファイルを追加 |
| CI/CD での扱い | GitHub Secrets や環境変数として安全に管理 |
.gitignore への追加
# OTPシークレット
.otp_secrets
トラブルシューティング
OTP が一致しない場合
時刻がずれている可能性があります:
# システム時刻を確認
date
# NTPで同期(macOS)
sudo sntp -sS time.apple.com
# NTPで同期(Linux)
sudo timedatectl set-ntp true
シークレットキーが無効な場合
- Base32形式であることを確認(A-Z, 2-7 の文字のみ)
- スペースやハイフンを削除
- 大文字に統一
コマンドリファレンス
# 基本的なTOTP生成
oathtool --totp --base32 "SECRET"
# 8桁のコード(一部サービスで使用)
oathtool --totp --base32 --digits=8 "SECRET"
# 時間ステップを変更(デフォルトは30秒)
oathtool --totp --base32 --time-step-size=60 "SECRET"
# 次のOTPも表示(切り替わるタイミング用)
oathtool --totp --base32 -w 1 "SECRET"
まとめ
oath-toolkit を使えば、CLI から簡単に OTP を取得できます。
- インストール:
brew install oath-toolkit(macOS) - シークレットキー取得: 2FA設定時に必ずメモ
- OTP生成:
oathtool --totp --base32 "SECRET" - 自動化: シェル関数や Playwright と組み合わせ
AI エージェントや E2E テストでの 2FA 対応が必要な場面で、ぜひ活用してみてください。