この記事では、Amplify SDK(JavaScript)を使い、Cognitoの認証機能を試してみたいと思います。
ただ、Amplify でアプリを作成したいわけではないので、amplify initなどは使わず、Amplify SDKだけを利用する形で検証してみたいと思います。

これができれば、既存のアプリにCognitoを組み込みたい場合にも都合が良さそうです。

登場人物

今回はホストされたUIは利用せず、UIを自作した上でAPIを直接呼び出して、サインアップ、サインインなどの処理を行います。

  • Cognito ユーザプール
  • サインアップ画面
  • コード確認画面
  • サインイン画面
  • 現在のセッション確認画面
  • パスワード変更画面
  • パスワード忘れ画面

ユーザプールを作成

AWSコンソール画面からユーザプールを作成します。
APIの検証が主目的なので、最もシンプルな構成にしようと思います。

1.サインインの設定

サインインエクスペリエンスを設定します。


ユーザープールだけを利用する設定にしました。
Eメールを選択したので、ユーザはEメールでサインインする想定です。

2.セキュリティ要件の設定

セキュリティ要件を設定します。


パスワードはデフォルト設定のままです。


多要素認証(MFA)は無しにしました。


パスワードを忘れた場合に、自分で再登録できるようにしました。

3.サインアップの設定

サインアップエクスペリエンスを設定します。


サインアップ画面からユーザが自分自身でサインアップできるようにしたいので、自己登録にチェックを入れます。


なんとなく、ニックネームも登録するようにしてみました。

4.メッセージ配信の設定

メッセージ配信を設定します。


今回は検証用で、メール件数が50件/日を超えることはないので、CognitoでEメールを送信するようにしました。

5.アプリケーションの設定

アプリケーションを統合します。


今回はホストされたUIは使いません。
自分で画面を作って、その中でAPIを呼び出します。


ブラウザから認証するので「パブリッククライアント」を選択しました。
また、「クライアントのシークレットを生成しない」を選択しました。
これは、JavaScriptのAmplify SDKが、2022年1月現在はまだクライアントシークレットを指定して認証処理を行うことに対応してないためです。


「高度なアプリケーションクライアントの設定」および「属性の読み取りおよび書き込み許可」ともに、デフォルト設定のままです。
SRP(セキュアリモートパスワード)がよくわかってないですが、通信時に生のパスワードをそのまま使うのではなくて、よりセキュアな方法らしいです。

ここまでで、ユーザープールを作成が完了しました。

認証付きWebアプリ作成

こちらを参考にしつつ、とはいえAmplifyでアプリを作るわけではなく、Amplify SDKだけを利用して、認証機能付きのWebアプリを作成してみます。

フォルダ/ファイル構成

最終的にフォルダ/ファイル構成は以下のようになりました。
サインアップ、サインインなど個別に画面を作って、それぞれ専用のJavaScriptのファイルが作ってる感じです。

├── dist
├── node_modules
├── public
│   ├── index.html
│   ├── sign-up.html
│   ├── confirm-sign-up.html
│   ├── sign-in.html
│   ├── current-session.html
│   ├── sign-out.html
│   ├── change-password.html
│   └── forgot-password.html
├── src
│   ├── auth.js
│   ├── sign-up.js
│   ├── confirm-sign-up.js
│   ├── sign-in.js
│   ├── current-session.js
│   ├── sign-out.js
│   ├── change-password.js
│   └── forgot-password.js
├── package.json
└── webpack.config.js

package.json

webpack以外で実際に使ってるライブラリは、aws-amplifyだけです。

{
  "name": "cognito-amplify-sample",
  "version": "1.0.0",
  "license": "MIT",
  "dependencies": {
    "aws-amplify": "latest"
  },
  "devDependencies": {
    "copy-webpack-plugin": "^6.1.0",
    "webpack": "^4.46.0",
    "webpack-cli": "^4.9.1",
    "webpack-dev-server": "^4.4.0"
  },
  "scripts": {
    "start": "webpack && webpack-dev-server --mode development",
    "build": "webpack"
  }
}

webpack.config.js

各画面用のJavaScriptファイルをそれぞれバンドルしてます。
HTMLファイルは、copy-webpack-pluginを使ってコピーしてるだけです。

const CopyWebpackPlugin = require("copy-webpack-plugin");
const webpack = require("webpack");
const path = require("path");

module.exports = {
  mode: "development",
  entry: {
    "sign-up": "./src/sign-up.js",
    "confirm-sign-up": "./src/confirm-sign-up.js",
    "sign-in": "./src/sign-in.js",
    "current-session": "./src/current-session.js",
    "sign-out": "./src/sign-out.js",
    "change-password": "./src/change-password.js",
    "reset-password": "./src/reset-password.js",
  },
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
      },
    ],
  },
  devServer: {
    client: {
      overlay: true,
    },
    hot: true,
    watchFiles: ["src/*", "public/*"],
  },
  plugins: [
    new CopyWebpackPlugin({
      patterns: ["public"],
    }),
    new webpack.HotModuleReplacementPlugin(),
  ],
};

auth.js

こちら を参考に設定しました。
コメントに書いてあるように、aws_user_pools_web_client_idを設定する場合は、クライアントシークレットは無効化しておく必要がありますので、注意が必要です。

import Amplify from "aws-amplify";

export const initAuth = () => {
  Amplify.configure({
    aws_cognito_region: "ap-northeast-1", // (required) - Region where Amazon Cognito project was created
    aws_user_pools_id: "us-west-2_xxxxxxxxx", // (optional) -  Amazon Cognito User Pool ID
    aws_user_pools_web_client_id: "xxxxxxxxxxxxxxxxxxxxxxx", // (optional) - Amazon Cognito App Client ID (App client secret needs to be disabled)
  });
};

サインアップ画面

サインアップ(ユーザ登録)をするための画面を作成したいと思います。

  • sign-up.html
    今回は、サインインに利用するユーザ属性をEメールとし、nicknameを追加の属性としたので、emailnicknamepasswordの三つの項目が必要になります
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Sign Up</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </head>
      <body>
        <div id="app">
          <h1>Sign up</h1>
          <form id="sign-up">
            <table>
              <tr>
                <td>email</td>
                <td><input type="email" id="email" /></td>
              </tr>
              <tr>
                <td>nickname</td>
                <td><input type="text" id="nickname" /></td>
              </tr>
              <tr>
                <td>password</td>
                <td><input type="password" id="password" /></td>
              </tr>
            </table>
            <div><button type="submit">sign-up</button></div>
          </form>
          <br />
          <a id="resend-sign-up" href="">resend-confirm-code</a>
        </div>
        <script src="sign-up.bundle.js"></script>
      </body>
    </html>
  • sign-up.js
    attachEventlistener()sign-upsubmitイベントとresend confirm codeclickイベントをリッスンするようにしてます。
    Auth.signUp()でサインアップ処理を実行しています。追加したnicknameattributesの方で指定します。
    Auth.resendSignUp()で確認コード再送処理を実行しています。

    import { Auth } from "aws-amplify";
    import { initAuth } from "./auth";
    
    class App {
      constructor() {
        initAuth();
        this.attachEventlistener();
      }
    
      /** UIにイベントをアタッチする */
      attachEventlistener() {
        // sign-up form
        document
          .getElementById("sign-up")
          .addEventListener("submit", async (event) => {
            event.preventDefault();
            const email = document.getElementById("email").value;
            const nickname = document.getElementById("nickname").value;
            const password = document.getElementById("password").value;
            if (!email || !nickname || !password) {
              alert("Please input email, nickname and password.");
              return;
            }
            await this.signUp(email, nickname, password);
          });
    
        // resend-sign-up link
        document
          .getElementById("resend-sign-up")
          .addEventListener("click", async (event) => {
            event.preventDefault();
            const email = document.getElementById("email").value;
            if (!email) {
              alert("Please input email.");
              return;
            }
            await this.resendSignUp(email);
          });
      }
    
      /** サインアップを実行する */
      async signUp(email, nickname, password) {
        try {
          const result = await Auth.signUp({
            username: email,
            password,
            attributes: { nickname },
          });
          console.log(result);
        } catch (error) {
          console.log(error);
          alert(error.message);
        }
      }
    
      /** 確認コードを再送する */
      async resendSignUp(email) {
        try {
          const result = await Auth.resendSignUp(email);
          console.log(result);
        } catch (error) {
          console.log(error);
          alert(error.message);
        }
      }
    }
    
    new App();
  • 画面確認(http://localhost:8080/sign-up.html
    実際にサインアップを実行すると、以下のようにコンソールに結果が表示されました。

    認証フローとしてUSER_SRP_AUTHが利用されていることが分かります。
  • AWSコンソール確認
    サインアップを実行すると、ユーザプールにユーザが登録されました。
    「Eメール確認済み」が「いいえ」、「確認ステータス」が「未確認」で、ユーザが登録されていることが確認できました。
  • メール確認
    「Your verification code」というタイトルで、メールで確認コードが通知されす。
  • 発生するエラー
    色々なエラーが発生しますが、自分が遭遇したエラーを列挙しておきます。
    • signUp()
      • InvalidPasswordException: Password did not conform with policy: Password must have lowercase characters
        • パスワードがポリシーを満たしてないときに発生します。
      • InvalidPasswordException: Password did not conform with policy: Password not long enough
        • パスワードの長さが足りないときに発生します。
      • InvalidParameterException: Attributes did not conform to the schema: nickname: The attribute is required
        • nicknameが必要なのに、実装ミスでsignUp()の引数にattributesを指定し忘れてるときに発生しました。
      • UsernameExistsException: An account with the given email already exists.
        • ユーザ名がすでに登録されている場合に発生します。
        • このケースは、resend confirm codeをクリックすることで、確認コードを再送するイメージです。
    • resendSignUp()
      • InvalidParameterException: User is already confirmed.
        • ユーザがすでに「確認済」のステータスの場合に発生します。

コード確認画面

サインアップを実行すると、確認コードがメールで通知されます。
この確認コードを登録するためのコード確認画面を作成します。
これにより、メール確認およびユーザ確認をまとめて行うことができます。

  • confirm-sign-up.html
    emailcodeの2項目が必要になります。
    このcodeにメールで通知された6桁の確認コードを入力します。
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Confirm Sign Up</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </head>
      <body>
        <div id="app">
          <h1>Confirm Sign Up</h1>
          <h5>Please input confirm code on your email address.</h5>
          <form id="confirm-sign-up">
            <table>
              <tr>
                <td>email</td>
                <td><input type="email" id="email" /></td>
              </tr>
              <tr>
                <td>code</td>
                <td><input type="password" id="code" /></td>
              </tr>
            </table>
            <div><button type="submit">confirm</button></div>
          </form>
        </div>
        <script src="confirm-sign-up.bundle.js"></script>
      </body>
    </html>
  • confirm-sign-up.js
    特に説明はいらないと思いますが、submitイベントをリッスンして、その中でconfirmSignUp()を呼び出しています。

    import { Auth } from "aws-amplify";
    import { initAuth } from "./auth";
    
    class App {
      constructor() {
        initAuth();
        this.attachEventlistener();
      }
    
      /** UIにイベントをアタッチする */
      attachEventlistener() {
        document
          .getElementById("confirm-sign-up")
          .addEventListener("submit", async (event) => {
            event.preventDefault();
            const email = document.getElementById("email").value;
            const code = document.getElementById("code").value;
            if (!email || !code) {
              alert("Please input email and code.");
              return;
            }
            await this.confirmSignUp(email, code);
          });
      }
    
    /** コードを確認する */
      async confirmSignUp(email, code) {
        try {
          const result = await Auth.confirmSignUp(email, code);
          console.log(result);
        } catch (error) {
          console.log(error);
          alert(error.message);
        }
      }
    }
    
    new App();
  • 画面確認(http://localhost:8080/confirm-sign-up.html
    メールで通知された確認コードを入力する必要があります。
    ボタンを押して、コンソールのを見るとSUCCESSという文字列が出力されました。
  • AWSコンソール確認
    「Eメール確認済み」が「はい」に、「確認ステータス」が「確認済み」に変わっていることが確認できました。
  • 発生するエラー
    • CodeMismatchException: Invalid verification code provided, please try again.
      • 入力した確認コードが間違っているときに発生します。
    • ExpiredCodeException: Invalid code provided, please request a code again.
      • 入力した確認コードが期限切れやすでに利用済みの場合に発生します。

サインイン画面

サインイン(ログイン)をするための画面を作成したいと思います。

  • sign-in.html
    emailpasswordが必須入力の項目です。
    サインインが成功した場合、取得したid-tokenを表示するようにしてます。
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Sign In</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <style>
          textarea {
            width: 500px;
          }
        </style>
      </head>
      <body>
        <div id="app">
          <h1>Sign In</h1>
          <form id="sign-in">
            <table>
              <tr>
                <td>email</td>
                <td><input type="email" id="email" /></td>
              </tr>
              <tr>
                <td>password</td>
                <td><input type="password" id="password" /></td>
              </tr>
            </table>
            <div>
              <button type="submit">sign-in</button>
            </div>
          </form>
          <div class="result">
            <div>id-token</div>
            <textarea id="id-token" readonly></textarea>
          </div>
        </div>
        <script src="sign-in.bundle.js"></script>
      </body>
    </html>
  • sign-in.js
    Auth.signIn()でサインインしているだけです。
    サインインが成功したら、id-tokenを取得できますので、それを画面に表示しています。

    import { Auth } from "aws-amplify";
    import { initAuth } from "./auth";
    
    class App {
      constructor() {
        initAuth();
        this.attachEventlistener();
      }
    
      /** UIにイベントをアタッチする */
      attachEventlistener() {
        document
          .getElementById("sign-in")
          .addEventListener("submit", async (event) => {
            event.preventDefault();
            const email = document.getElementById("email").value;
            const password = document.getElementById("password").value;
            if (!email || !password) {
              alert("Please input email and password.");
              return;
            }
            await this.signIn(email, password);
          });
      }
    
      /** サインインを実行する */
      async signIn(email, password) {
        try {
          const result = await Auth.signIn(email, password);
          console.log(result);
          document.getElementById("id-token").value =
            result.signInUserSession.idToken.jwtToken;
        } catch (error) {
          console.log(error);
          alert(error.message);
        }
      }
    }
    
    new App();
  • 画面確認(http://localhost:8080/sign-in.html
    無事サインインできて、id-tokenを取得することができています。
    コンソールにAuth.signIn()の戻り値を出力しているのですが、トークンだけでなく、id-tokenpayloadがすでに復号化されて入ってるので、ユーザ属性を取得するのにも便利です。
  • ローカルストレージ確認
    中身は良くわかってないですが、サインインが成功するとローカルストレージにもデータが保存されます。
    このデータは、Auth.currentSession()などで利用されます。
  • 発生するエラー
    • NotAuthorizedException: Incorrect username or password.
      • emailpasswordが間違っている場合に発生します。

現在のセッション確認画面

現在のセッションを確認する画面を作成します。

  • current-session.html
    現在のセッション情報を取得して、emailnicknameid-tokenの3項目を表示する画面だけの画面になります。
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Current Session</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <style>
          textarea {
            width: 500px;
          }
        </style>
      </head>
      <body>
        <div id="app">
          <h1>Current Session</h1>
          <div>email</div>
          <input type="text" id="email" readonly></input>
          <div>nickname</div>
          <input type="text" id="nickname" readonly></input>
          <div>id-token</div>
          <textarea id="id-token" readonly></textarea>
        </div>
        <script src="current-session.bundle.js"></script>
      </body>
    </html>
  • current-session.js
    Auth.currentSession()で現在のセッション情報を取得して画面に表示しています。
    引数が何もないのですが、ローカルストレージの情報を利用しているようです。

    import { Auth } from "aws-amplify";
    import { initAuth } from "./auth";
    
    class App {
      constructor() {
        initAuth();
        this.currentSession();
      }
    
      /** 現在のセッションを取得する */
      async currentSession() {
        try {
          const session = await Auth.currentSession();
          console.log(session);
          document.getElementById("email").value = session.idToken.payload.email;
          document.getElementById("nickname").value =
            session.idToken.payload.nickname;
          document.getElementById("id-token").value = session.idToken.jwtToken;
        } catch (error) {
          console.log(error);
        }
      }
    }
    
    new App();
  • 画面確認(http://localhost:8080/current-session.html
    無事、セッション情報が取得できています。
    サインアウトしたり、ローカルストレージのデータを消したりすると、情報を取得できません。
  • 発生するエラー
    • No current user
      • エラーではないですが、サインインしていない状態だと、この文字列が返却されます。

パスワード変更画面

サインインした状態で、パスワードを変更する画面を作成しました。

  • change-password.html
    現在のパスワードと新しいパスワードの2項目が必要です。
    サインインしている前提なので、emailのような項目は必要ありません。
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Change Password</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <style>
          textarea {
            width: 500px;
          }
        </style>
      </head>
      <body>
        <div id="app">
          <h1>Change Password</h1>
          <form id="change-password">
            <table>
              <tr>
                <td>current-password</td>
                <td><input type="password" id="current-password" /></td>
              </tr>
              <tr>
                <td>new-password</td>
                <td><input type="password" id="new-password" /></td>
              </tr>
            </table>
            <div>
              <button type="submit">change-password</button>
            </div>
          </form>
        </div>
        <script src="change-password.bundle.js"></script>
      </body>
    </html>
  • change-password.js
    ポイントは、Auth.currentAuthenticatedUser()で現在の認証済みユーザを取得して、そのユーザを第一引数にAuth.changePassword()を呼び出している部分です。

    import { Auth } from "aws-amplify";
    import { initAuth } from "./auth";
    
    class App {
      constructor() {
        initAuth();
        this.attachEventlistener();
      }
    
      /** UIにイベントをアタッチする */
      attachEventlistener() {
        document
          .getElementById("change-password")
          .addEventListener("submit", async (event) => {
            event.preventDefault();
            const currentPassword =
              document.getElementById("current-password").value;
            const newPassword = document.getElementById("new-password").value;
            if (!currentPassword || !newPassword) {
              alert("Please input current-password and new-password.");
              return;
            }
            await this.changePassword(currentPassword, newPassword);
          });
      }
    
      /** パスワード変更を実行する */
      async changePassword(currentPassword, newPassword) {
        try {
          const user = await Auth.currentAuthenticatedUser();
          console.log(user);
          const result = await Auth.changePassword(
            user,
            currentPassword,
            newPassword
          );
          console.log(result);
        } catch (error) {
          console.log(error);
          alert(error.message);
        }
      }
    }
    
    new App();
  • 画面確認(http://localhost:8080/change-password.html
    古いパスワードと新しいパスワードを入力してボタンをクリックすると、無事パスワードを変更できました。SUCCESSという文字列が返ってきています。
    実際にサインイン画面で新しいパスワードでサインインできました。
  • 発生するエラー
    • LimitExceededException: Attempt limit exceeded, please try after some time.
      • 何度かパスワードを間違うとこのエラーが発生します。

パスワード忘れ画面

パスワードを忘れた場合に、パスワードを再登録を実施するための画面を作成しました。
確認コードをメールで通知し、確認コードと一緒に新しいパスワードを入力する画面になります。

  • forgot-password.html
    確認コードをメール通知する機能と、確認コードを使って新しいパスワードを登録する機能を提供します。
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Forgot Password</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </head>
      <body>
        <div id="app">
          <h1>Forgot Password</h1>
          <h5>If you forgot your password, you can reset your password.</h5>
          <h3>Send Mail</h3>
          <form id="forgot-password">
            <table>
              <tr>
                <td>email</td>
                <td><input type="email" id="email" /></td>
              </tr>
            </table>
            <div>
              <button type="submit">forgot-password</button>
            </div>
          </form>
          <h3>Submit</h3>
          <form id="forgot-password-submit">
            <table>
              <tr>
                <td>email</td>
                <td><input type="email" id="email" /></td>
              </tr>
              <tr>
                <td>code</td>
                <td><input type="password" id="code" /></td>
              </tr>
              <tr>
                <td>password</td>
                <td><input type="password" id="password" /></td>
              </tr>
            </table>
            <div>
              <button type="submit">forgot-password-submit</button>
            </div>
          </form>
        </div>
        <script src="forgot-password.bundle.js"></script>
      </body>
    </html>
  • forgot-password.js
    二つのフォームにイベントリスナーをアタッチしています。
    Auth.forgotPassword()で確認コードをメール通知し、Auth.forgotPasswordSubmit()で新しいパスワードを登録しています。

    import { Auth } from "aws-amplify";
    import { initAuth } from "./auth";
    
    class App {
      constructor() {
        initAuth();
        this.attachEventlistener();
      }
    
      /** UIにイベントをアタッチする */
      attachEventlistener() {
        // forgot-password form
        document
          .getElementById("forgot-password")
          .addEventListener("submit", async (event) => {
            event.preventDefault();
            const email = document.getElementById("email").value;
            if (!email) {
              alert("Please input email.");
              return;
            }
            await this.forgotPassword(email);
          });
    
        // forgot-password-submit form
        document
          .getElementById("forgot-password-submit")
          .addEventListener("submit", async (event) => {
            event.preventDefault();
            const email = document.getElementById("email").value;
            const code = document.getElementById("code").value;
            const password = document.getElementById("password").value;
            if (!email || !code || !password) {
              alert("Please input email, code and password.");
              return;
            }
            await this.forgotPasswordSubmit(email, code, password);
          });
      }
    
      /** 確認コードを通知する */
      async forgotPassword(email) {
        try {
          const result = await Auth.forgotPassword(email);
          console.log(result);
        } catch (error) {
          console.log(error);
          alert(error.message);
        }
      }
    
      /** 確認コードを使って新しいパスワードを設定する */
      async forgotPasswordSubmit(email, code, password) {
        try {
          const result = await Auth.forgotPasswordSubmit(email, code, password);
          console.log(result);
        } catch (error) {
          console.log(error);
          alert(error.message);
        }
      }
    }
    
    new App();
  • 画面確認(http://localhost:8080/forgot-password.html
    forgot-passwordで確認コードがメール通知されました。内容は、サインアップの時と全く同じです。
    また、forgot-password-submitで新しいパスワードが登録されました。

Amplify SDKのインターフェースがシンプルすぎて、わざわざ確認しなくても分かる気がしなくもないですが、一通りベーシックな認証の機能を確認できました。

その他

クライアントシークレットについて

クライアントシークレットの作成をした場合、CognitoのAPIを呼び出した際に、以下のようにエラーが発生しました。

Client xxxxx is configured for secret but secret was not received

これに関しては、こちらのISSUE で上がっているのですが、Amplify SDK(JavaScript)では現在クライアントシークレットを指定するいことはできないみたいです。
製作者側も検討中とのことですが、今のところはクライアントシークレットを作成するのチェックを外すのが良さそうです。

refresh-tokenを使ったid-tokenの再発行

id-tokenが期限切れの場合に、refresh-tokenを使ってid-tokenを再発行するのだと思って、Amplify SDKのインターフェースを確認してみたのですが、それらしい関数が見当たりません。
ググってみると、StackOverflowに以下のQ&Aがありました。
https://stackoverflow.com/questions/53375350/how-handle-refresh-token-service-in-aws-amplify-js

結論としては、Auth.currentSession()を行うと、id-tokenの期限が切れている場合に、
勝手にid-tokenを再発行してくれるらしいです。
なので、id-tokenを利用する場合は、毎度Auth.currentSession()を実行する必要があるようです。

さいごに

今回、Amplify SDKでCognitoの認証機能を試してみましたが、特にAmplifyでアプリを作成しなくても、SDK だけを使ってちゃんと動いてくれました。
Amplify SDKのインターフェースも非常に分かりやすいので、特にドキュメントを読み込んだりしなくても、普通に実装できると思います。

今回は試してないのですが、気が向いたら以下のような点も今後試してみようと思います。

  • 認証イベントの前後でLambdaトリガーをしこむ
    • 例)ユーザ移行に利用。サインアップ時にユーザープールに存在しなかったら、既存のDBからデータを取得して、ユーザプールにデータを登録する
  • ユーザをCSVでまとめてインポートする
  • CognitoをAWS GatewayのAuthenticatorとして設定し、トークンをチェックする
  • Admin用のAPIで、直接パスワードを変更したり、ユーザのステータスを変更したりする