いわむぶろぐ

Webエンジニア@スタートアップ@のんびり綴ってます。

Amazon Cognitoの新規ユーザー認証フローと自分たちの要件が違う場合のTips

Amazon Cognitoでメールアドレス認証&変更機能を実装しようと思っていました。しかしそこで後述する問題点があり、素直に利用することはできませんでした。

本記事ではその問題点や打開策を中心に紹介します。

Cognito前提知識

データ

Cognitoはユーザーの属性(氏名、住所、電話番号などをUserPoolに保存できます。

メールアドレスに関する属性は、メールアドレス値(email)と、メールアドレス検証ステータス(email_verified)の2つがあります。

API

amazon-cognito-identity-jsを利用することで、メールアドレス変更に関する以下の3つのAPIを利用できます。

1. UpdateUserAttributes

  • Cognitoユーザーの属性を変更する
  • 新しいメアドに認証コードを送る
cognitoidentityserviceprovider.updateUserAttributes(
  {
    AccessToken: accessToken,
    UserAttributes: [
      {
        Name: "email",
        Value: {{newEmail}} // 新しいメールアドレス
      }
    ]
  },
)

2. VerifyUserAttribute

  • 受け取った認証コードをこのAPIに送信することでメールアドレスを検証し、検証ステータス属性を変更する
cognitoidentityserviceprovider.verifyUserAttribute(
  {
    AccessToken: accessToken,
    AttributeName: "email",
    Code: {{passcode}} // 新しいメアドに送られた認証コード
  },
)   

3. AdminUpdateUserAttributes

  • 管理者権限でユーザーの属性を変更する
  • メールアドレスを変更しても、認証コードを送らずに認証済みにすることも可能
cognitoidentityserviceprovider.adminUpdateUserAttributes(
  {
    UserAttributes: [
      {
        Name: "email",
        Value: {{newEmail}}
      },
      {
        Name: "email_verified",
        Value: "true"
      }
    ],
    Username: {{cognitoUsername}},
    UserPoolId: {{userPoolId}}
  },
)

今回の仕様と、元々の設計

仕様

  • ユーザーが新しいメアドを入力する
  • 新しいメアドに認証コード(6桁)が送信される
  • ユーザーが認証コードを入力することで、メアドの変更が完了となる

設計

問題点

以下の問題点があり、スタンダードに利用することはできませんでした

検証が完了する前に、メールアドレスが変更されてしまう

UpdateUserAttributes APIを利用した時点で、メールアドレス値を新しいメールアドレスに書き換えてしまいます。 つまり、VerifyUserAttribute APIで検証しなくてもメールアドレスはすでに書き換わっており、元のメールアドレスのデータは消えてしまいます。

そうなることで以下の問題が発生してしまいます。

  • 間違えたメールアドレスでUpdateUserAttributes APIを利用しても、検証無しでメールアドレスデータは書き換わるので、セッションが切れたら再ログインしにくくなる。
  • 検証が無いため、他人のメールアドレスをフォームに入力した時点で自分のメールアドレスとして登録できてしまう。悪用に繋がる可能性がある。

実装した打開策

実際に以下の設計で機能を作ることにしました。

メールアドレスの認証を完了させるところまでは自分たちのシステム側で行う

手順

メール送信時

  • Amazon ElastiCacheを利用し、新しいメールアドレスと認証コードのペアを保存する
    • key: 認証コード、value: 新しいメールアドレス + ユーザーの識別子
    • 保存時にTTLを設定し、認証コードの有効期限として利用
  • Amazon SESを利用して、新しいメールアドレスに認証コードを送信する

メール認証時

  • Amazon ElastiCacheのデータを参照し、新しいメールアドレスと認証コードのペアがあるかを確認する
  • AdminUpdateUserAttributes API を利用し、新しいメアドのデータを新しいものに変換する
    • メールアドレスの認証までを完了させているので、AdminUpdateUserAttributes APIを利用して検証済みステータスごと更新する。

まとめ

Cognitoユーザーの属性の「メールアドレス値」は、メールアドレスの検証を完了しなくても変更されます。

※ Cognitoのパスワード変更機能は専用のAPIが用意されており、認証が終わるまで変更はされません。 なのでそこの差異も注意しておかないと設計漏れが発生してしまうこともあるかと思います。

この記事が役に立ってくれると幸いです。