Amazon Cognito でユーザーアカウント復旧時に古い回復用コードが使えるのか確認してみた

2023.06.15

いわさです。

Amazon Cognito のユーザープールではユーザーがパスワードを忘れた際に、メールアドレスや電話番号宛に回復用コードを送信してパスワードの再設定ができるユーザーアカウント復旧機能が備わっています。

この回復用コードは次の公式ドキュメントによると 1 時間有効です。

ただしこの回復用コードは、ユーザーが要求する度に新しいものが発行されます。
そうした時に、ユーザーは複数のコードを入手することが出来るわけですが、これらのコードは発行から 1 時間以内であれば全て有効なのでしょうか。

上記ドキュメントに記述が見当たらなかったので実際に AWS CLI を使って検証してみました。
Cognito ユーザプールで回復用コードの発行・検証方法の流れを知らない方も良ければ参考にしてもらえると。

未使用の回復用コードを複数発行して使ってみる

前提として、ユーザープールには次のようにユーザーが作成済みとします。
また、このユーザーの E メールアドレスは検証済みです。未検証の場合は期待した送信先に回復用コードが発行されませんでした。

ユーザープールのアカウント復旧設定は次のようなデフォルトの設定になっています。

回復用コードの発行

回復用コードの発行ですが、forgot-passwordコマンドから実行することが出来ます。

入力パラメータはクライアント ID と復旧対象のユーザー名です。
次のように 2 コマンドを実行しています。

% cat forgot-password.json
{
    "ClientId": "7vsusu8vbv4eh9vvcuk548d022",
    "Username": "80ff2f32-b5ea-4c02-9348-1b16f45f56a7"
}
% aws cognito-idp forgot-password --cli-input-json file://forgot-password.json
{
    "CodeDeliveryDetails": {
        "Destination": "i***@c***",
        "DeliveryMedium": "EMAIL",
        "AttributeName": "email"
    }
}
% aws cognito-idp forgot-password --cli-input-json file://forgot-password.json
{
    "CodeDeliveryDetails": {
        "Destination": "i***@c***",
        "DeliveryMedium": "EMAIL",
        "AttributeName": "email"
    }
}

そうすると次のように回復用コードがメールアドレス(上記のDestination)宛に送信されます。

1 回目に受信したメール本文

Your password reset code is 350768

2 回目に受信したメール本文

Your password reset code is 033448

回復用コードの使用

では回復用コードを使ってパスワード再設定を行います。
confirm-forgot-passwordコマンドの入力に回復用コードと新しいパスワードを指定します。

古いコードは無効

先に発行された古い回復用コードを 2 回目の発行後に使ってみました。

% cat confirm-forgot-password-1.json
{
    "ClientId": "7vsusu8vbv4eh9vvcuk548d022",
    "Username": "80ff2f32-b5ea-4c02-9348-1b16f45f56a7",
    "ConfirmationCode": "350768",
    "Password": "111111"
}
% aws cognito-idp confirm-forgot-password --cli-input-json file://confirm-forgot-password-1.json

An error occurred (CodeMismatchException) when calling the ConfirmForgotPassword operation: Invalid verification code provided, please try again.

エラーになりました。
回復用コードが無効だと言われていますね。どうやら新しいコードを発行したタイミングで無効化された様子です。

新しいコードは有効

念のため新しいコードでも試してみましょう。

% cat confirm-forgot-password-2.json
{
    "ClientId": "7vsusu8vbv4eh9vvcuk548d022",
    "Username": "80ff2f32-b5ea-4c02-9348-1b16f45f56a7",
    "ConfirmationCode": "033448",
    "Password": "222222"
}
% aws cognito-idp confirm-forgot-password --cli-input-json file://confirm-forgot-password-2.json

こちらはエラーが発生せずにコマンドが正常終了しました。
新しいパスワードでログインしてみましょう。

% cat initiate-auth2.json
{
    "AuthFlow": "USER_PASSWORD_AUTH",
    "AuthParameters": {
        "USERNAME": "80ff2f32-b5ea-4c02-9348-1b16f45f56a7",
        "PASSWORD": "222222"
    },
    "ClientId": "7vsusu8vbv4eh9vvcuk548d022"
}
% aws cognito-idp initiate-auth --cli-input-json file://initiate-auth2.json                     
{
    "ChallengeParameters": {},
    "AuthenticationResult": {
        "AccessToken": "cccccccc",
        "ExpiresIn": 3600,
        "TokenType": "Bearer",
        "RefreshToken": "bbbbbbbb",
        "IdToken": "aaaaaaaa"
    }
}

ログインに成功しました。回復用コードを使ってパスワードが更新出来ていますね。

さいごに

本日は Amazon Cognito でユーザーアカウント復旧時に古い回復用コードが使えるのか確認してみました。
新しい回復用コードを発行すると、古いコードは使えなくなることが確認出来ました。

結果として期待どおりの動きではあったのですが ID トークンなどのようにステートレスで期限が切れるまではどれも有効である、という可能性ももしかしたらあるかもと少し思っていたので確認出来てよかったです。