【ようやく解決】Cognitoのemail変更をさくっとやる方法【サンプルつき】

今回はCognitoの話し。
長年CognitoはupdateUserAttributesにおけるemail変更プロセスの課題を放置してましたが、ここ最近その解消が成されたようです。

email変更の課題

updateUserAttributesにてusername(email)を変更した際、認証コードをチェックしていないにも関わらずid(email)の変更が完了してしまう。(email_verifiedがfalseの状態)

認証コードが正常に入力されればemail_verifiedがtrueとなりログインは可能

しかし、変更後のemailに誤入力がある場合は認証コードが届かずemail_verifiedがfalseのままであるため次回のログインが成功しないことになる。

この問題がどうも2022年の5月頃にあったAWSの仕様変更にて解消されたもよう。
課題解決のキーとなるのはCognitoの新しいコンソール出てきた「サインアップエクスペリエンス」が肝となる。

Cognito サインアップエクスペリエンス
Cognito 属性変更の確認

「属性変更の確認」から「未完了の更新があるときに元の属性値をアクティブに保つ – 推奨」にチェックして保存。

これにより

認証コードをチェックしていないにも関わらずid(email)の変更が完了してしまう。

この問題が解消されます。

あとは従来通りの流れで変更処理を実装していけば目標達成です。
おさらいしておきます。

email変更の流れ

1.Cognito新コンソールで左記の設定をおこなう

2.ユーザのメールアドレス変更では「updateUserAttributes」を使う(AccessTokenが必要)

3.メール変更後ユーザに認証コードが飛ぶ(先の設定でemailはまだ変更されていない)

4.VerifyUserAttributeにてコードの検証をおこなう(AccessTokenが必要)

5.検証後、メールアドレスが書き換わる

updateUserAttributesではなく管理向けAPIのAdminUpdateUserAttributesがある。

$result = $this->client->AdminUpdateUserAttributes([
    'Username' => 'xxxxxxxx',
    'UserPoolId' => 'ap-northeast-1_xxxxxxxx',
    'UserAttributes' => [
        [
            'Name' => 'email',
            'Value' => 'xxxxx@xxxxx'
        ],
        [
            'Name' => 'email_verified',
            'Value' => 'false'
        ]
    ]
]);

これを使ってemailの変更は確かにおこなえはしますが、Usernameのエイリアスにemailを設定している場合、ログインIDとしてのUsernameであるemailは適用されないという不具合があります。

するとどうなるかというと、変更後のemailでログインできません。
変更前のemailであればログインできます。
ユーザからするとemailの変更はログインIDの変更と思って処理をするのにこれでは本末転倒です。

必要に応じて、ユーザーはサインイン時にエイリアスを使用して他の属性を入力できます。デフォルトでは、ユーザーは各自のユーザー名とパスワードでサインインします。ユーザー名はユーザーが変更できない固定値です。属性をエイリアスとしてマーキングすると、ユーザーはユーザー名の代わりにその属性を使用してサインインできます。E メールアドレス、電話番号、および任意ユーザー名属性は、エイリアスレコードとしてマーキングできます。例えば、E メールと電話をユーザープールのエイリアスとして選択すると、そのユーザープールのユーザーは、自分のユーザー名、E メールアドレス、または電話番号とパスワードを使ってサインインできます。

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-attributes.html

ユーザ名、エイリアスなどの理解は公式をウォッチしておくのが本流です。

最後にメールアドレスの書き換え要求と検証プロセスのコードを抜粋しておさらばしたいと思います。

// メールアドレス変更要求(検証コードがCognitoより飛ばされる)
$result = $this->client->updateUserAttributes([
    'AccessToken' => self::ACCESS_TOKEN,
    'UserAttributes' => [
        [
            'Name' => 'email',
            'Value' => 'xxxxx@xxxxx'
        ]
    ]
]);

// 検証コードの確認
$result = $this->client->verifyUserAttribute([
    'AccessToken' => self::ACCESS_TOKEN,
    'AttributeName' => 'email',
    'Code' => 'xxxxxx'
]);

良きCognitoライフを。