Amazon CognitoのAdminDeleteSoftwareTokenを直接呼び出してTOTP設定をリセットしてみた
はじめに
2026年8月26日、Amazon Cognitoに、管理者がユーザーのTOTP用ソフトウェアトークンを削除できるAdminDeleteSoftwareTokenが追加されました。TOTPデバイスを紛失したユーザーのトークンを削除し、MFAを再設定するためのAPIです。
| 項目 | AdminDeleteSoftwareToken追加前 | 追加後 |
|---|---|---|
| 管理者による対象ユーザーのTOTPリセット | 既存のTOTPトークンを削除する専用の管理者APIはない | AdminDeleteSoftwareToken で削除できる |
| MFA必須を維持したままの復旧 | ユーザープール全体のMFA設定の変更、またはユーザーの削除・再作成を検討する必要がある | 対象ユーザーのトークンを削除し、次回認証で返る MFA_SETUP から再設定フローを開始できる |
| 影響範囲 | ユーザープール全体、または対象ユーザーのID・関連データ | 対象ユーザーのソフトウェアトークン |
事前準備
検証はap-northeast-1で行いました。ユーザープールを作成したあと、ソフトウェアトークンMFAを有効にしてMFAを必須にし、パスワード認証用のアプリクライアントとダミーユーザーを用意しました。実際のIDやパスワードは掲載しないため、以下では変数を使用します。
MFA必須のユーザープール
まず、パスワード認証用のユーザープールを作成しました。
USER_POOL_ID=$(aws cognito-idp create-user-pool \
--pool-name totp-reset-test-pool \
--policies '{"PasswordPolicy":{"MinimumLength":8,"RequireUppercase":true,"RequireLowercase":true,"RequireNumbers":true,"RequireSymbols":false}}' \
--query 'UserPool.Id' --output text)
ソフトウェアトークンMFAを有効にし、プールのMFAを必須にしました。
aws cognito-idp set-user-pool-mfa-config \
--user-pool-id "$USER_POOL_ID" \
--mfa-configuration ON \
--software-token-mfa-configuration Enabled=true
アプリクライアントとダミーユーザー
パスワード認証を行うアプリクライアントを作成しました。
CLIENT_ID=$(aws cognito-idp create-user-pool-client \
--user-pool-id "$USER_POOL_ID" \
--client-name totp-test-client \
--no-generate-secret \
--explicit-auth-flows \
ALLOW_ADMIN_USER_PASSWORD_AUTH \
ALLOW_REFRESH_TOKEN_AUTH \
ALLOW_USER_PASSWORD_AUTH \
--query 'UserPoolClient.ClientId' --output text)
通知を送らないダミーユーザーを作成し、恒久パスワードを設定しました。
USERNAME=testuser
PASSWORD='<TestUserPassword>'
aws cognito-idp admin-create-user \
--user-pool-id "$USER_POOL_ID" \
--username "$USERNAME" \
--temporary-password "$PASSWORD" \
--message-action SUPPRESS
aws cognito-idp admin-set-user-password \
--user-pool-id "$USER_POOL_ID" \
--username "$USERNAME" \
--password "$PASSWORD" \
--permanent
ダミーユーザーはパスワード設定後にCONFIRMEDとなりました。認証したところMFA_SETUPチャレンジが返りました。
TOTP登録
恒久パスワードを設定したダミーユーザーに対し、MFA_SETUPのセッションを取得してTOTPを登録しました。
MFA_SETUP_SESSION="$(aws cognito-idp admin-initiate-auth \
--user-pool-id "$USER_POOL_ID" \
--client-id "$CLIENT_ID" \
--auth-flow ADMIN_USER_PASSWORD_AUTH \
--auth-parameters "USERNAME=$USERNAME,PASSWORD=$PASSWORD" \
--query Session --output text)"
ASSOCIATE_JSON="$(aws cognito-idp associate-software-token \
--session "$MFA_SETUP_SESSION" \
--output json)"
TOTP_SECRET="$(printf '%s' "$ASSOCIATE_JSON" | \
python3 -c 'import json,sys; print(json.load(sys.stdin)["SecretCode"])')"
ASSOCIATE_SESSION="$(printf '%s' "$ASSOCIATE_JSON" | \
python3 -c 'import json,sys; print(json.load(sys.stdin)["Session"])')"
ローカル環境にoathtoolを導入せずに済むよう、Dockerコンテナ内のoathtoolでコードを生成しました。TOTP_SECRETと生成したコードは標準出力に表示しません。
TOTP_CODE="$(docker run --rm -e "TOTP_SECRET=$TOTP_SECRET" alpine sh -c \
'apk add --no-cache oath-toolkit-oathtool >/dev/null && \
oathtool --totp --base32 "$TOTP_SECRET"')"
aws cognito-idp verify-software-token \
--session "$ASSOCIATE_SESSION" \
--user-code "$TOTP_CODE" \
--query Status --output text
SUCCESSが返ったあと、認証時にSOFTWARE_TOKEN_MFAチャレンジが返ることを確認しました。
API検証
事前準備でTOTPを登録したユーザーを対象に、削除前後で同じ項目を確認しました。
削除前の確認
認証要素
aws cognito-idp admin-get-user-auth-factors \
--user-pool-id "$USER_POOL_ID" \
--username "$USERNAME" \
--query ConfiguredUserAuthFactors --output json
[
"PASSWORD",
"SOFTWARE_TOKEN"
]
認証時のチャレンジ
aws cognito-idp admin-initiate-auth \
--user-pool-id "$USER_POOL_ID" \
--client-id "$CLIENT_ID" \
--auth-flow ADMIN_USER_PASSWORD_AUTH \
--auth-parameters "USERNAME=$USERNAME,PASSWORD=$PASSWORD" \
--query ChallengeName --output text
SOFTWARE_TOKEN_MFA
パスワードとソフトウェアトークンが認証要素に設定され、認証時にはTOTP用のチャレンジが返る状態です。
API実行
記事執筆時点で最新のAWS CLI 2.36.32とboto3 1.43.81は、AdminDeleteSoftwareTokenに未対応でした。
AWS CLIとboto3の代わりに、botocoreでSigV4署名を付与して直接呼び出しました。
import json
from urllib.request import Request, urlopen
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
from botocore.session import get_session
region = 'ap-northeast-1'
payload = {
'UserPoolId': 'ap-northeast-1_XXXXXXXXX',
'Username': 'testuser',
}
request = AWSRequest(
method='POST',
url=f'https://cognito-idp.{region}.amazonaws.com/',
data=json.dumps(payload, separators=(',', ':')).encode(),
headers={
'Content-Type': 'application/x-amz-json-1.0',
'X-Amz-Target': 'AWSCognitoIdentityProviderService.AdminDeleteSoftwareToken',
},
)
credentials = get_session().get_credentials().get_frozen_credentials()
SigV4Auth(credentials, 'cognito-idp', region).add_auth(request)
prepared = request.prepare()
with urlopen(
Request(prepared.url, data=prepared.body, headers=dict(prepared.headers.items()), method='POST')
) as response:
print(f'HTTP {response.status}')
print(response.read().decode() or '{}')
削除後の確認
AdminDeleteSoftwareTokenを実行したあと、削除前と同じコマンドで認証要素とパスワード認証時のチャレンジを確認しました。
認証要素
[
"PASSWORD"
]
ソフトウェアトークンが削除され、認証要素はパスワードだけになりました。
認証時のチャレンジ
MFA_SETUP
次回認証では、新しいソフトウェアトークンを設定できるMFA_SETUPチャレンジが返りました。
まとめ
SMS MFAなどの代替要素がなく、TOTPだけをMFA要素として利用するユーザーでは、デバイス紛失時の復旧が課題でした。AdminDeleteSoftwareTokenを使えば、対象ユーザーのTOTPだけをリセットし、次回認証でMFA_SETUPに戻して再登録を促す復旧フローを実装できます。
TOTPデバイス紛失時の復旧を理由にCognitoのMFA必須化を見送っていた場合は、このフローを試してみてください。
今後は、公式SDKのサポートや、パスキーを含むTOTP以外の認証要素についても、管理者が対象ユーザー単位でリセットできるAPIが提供されることに期待したいところです。







