Cognito をローカル環境に構築し、ユーザー認証機能まで作成する方法

## 概要

Cognito をローカル環境で構築およびユーザー認証までの手順を確認したので、情報共有および備忘録用としてメモしておきます。

また、参考までにこの記事で紹介している環境は、[github](https://github.com/Akiyoshi999/Cognito-local-environment) に載せておきます。

## 動作確認環境

- macOS Ventura 13.4
- Docker version 24.0.2
- Docker Compose version v2.18.1

## 前提条件

AWS CLI が設定されていること。

## ざっくりとした流れ

- motoserver を Docker で起動し、AWS サーバー Docker で起動する。
- ユーザープール作成
- アプリクライアント作成
- 管理者ユーザーの作成
- 管理者ユーザーのパスワード設定
- 管理者ユーザーステータスの確認
- 管理者ユーザーの認証

## 手順

### 次の `docker-compose.yml`を用意する。

```
version: "3"

services:
motoserver:
    image: motoserver/moto:latest
    ports:
    - "4000:4000"
    environment:
    - MOTO_PORT=4000
```

### motoserver の起動

`docker-compose`コマンド を実行して、motoserver を起動させる。

```
docker-compose up -d
```

### 環境変数の設定

次のコマンドを実行し、環境変数を設定する。パスワードや各値は適宜修正すること。

```
ENDPOINT_URL=http://localhost:4000
COGNITO_USER_NAME=MY_USER
COGNITO_USER_EMAIL=hogehoge@example.com
COGNITO_USER_PASSWORD=
```

### ユーザープールの作成

次のコマンドを実行し、ユーザープールを作成する。

```
USER_POOL_ID=$(
aws cognito-idp create-user-pool \
    --pool-name MyUserPool \
    --query UserPool.Id \
    --output text \
    --endpoint-url ${ENDPOINT_URL} \
)
```

### アプリクライアントの作成

次のコマンドを実行し、アプリクライアントを作成する。

```
CLIENT_ID=$(
aws cognito-idp create-user-pool-client \
    --client-name MyUserPoolClient \
    --user-pool-id ${USER_POOL_ID} \
    --output text \
    --query UserPoolClient.ClientId \
    --endpoint-url ${ENDPOINT_URL} \
)
```

### 管理者ユーザーの作成

次のコマンドを実行し、管理者ユーザーを作成する。

```
User=$(
  aws cognito-idp admin-create-user \
    --user-pool-id ${USER_POOL_ID} \
    --username ${COGNITO_USER_NAME} \
    --user-attributes Name=email,Value=${COGNITO_USER_EMAIL} Name=email_verified,Value=true \
    --message-action SUPPRESS \
    --endpoint-url ${ENDPOINT_URL} \
)
```

### 管理者ユーザーのパスワード設定

次のコマンドを実行し、管理者ユーザーのパスワードを設定する。

```
aws cognito-idp admin-set-user-password \
  --user-pool-id ${USER_POOL_ID} \
  --username ${COGNITO_USER_NAME} \
  --password ${COGNITO_USER_PASSWORD} \
  --permanent \
  --endpoint-url ${ENDPOINT_URL}
```

### 管理者ユーザーステータスの確認

次のコマンドを実行し、管理者ユーザーのステータスを確認する。

```
aws cognito-idp list-users \
  --user-pool-id ${USER_POOL_ID} \
  --query "Users[0].[Username,UserStatus]" \
  --endpoint-url ${ENDPOINT_URL}
```

`--query "Users[0].[Username,UserStatus]"`オプションでユーザー名と、ユーザーステータスの値のみ出力するようにしてます。
全ての出力を見たい場合は、このオプションを削除してください。
ユーザー名と`CONFIRMED`のステータスが表示されていれば OK です。

```
[
    "MY_USER",
    "CONFIRMED"
]
```

### 管理者ユーザーの認証

次のコマンドを実行し、管理者ユーザーの認証を実行する。

```
aws cognito-idp admin-initiate-auth \
  --user-pool-id ${USER_POOL_ID} \
  --client-id ${CLIENT_ID} \
  --auth-flow ADMIN_NO_SRP_AUTH \
  --auth-parameters "USERNAME=${COGNITO_USER_NAME},PASSWORD=${COGNITO_USER_PASSWORD}" \
  --endpoint-url ${ENDPOINT_URL} \
  --query "AuthenticationResult.IdToken"
```

こちらのコマンドでは`--query "AuthenticationResult.IdToken"`オプションでトークンの値のみ返却するように設定してます。
他の返り値もみたい場合は、このオプションを削除してください。

トークンが返ってきたら、ユーザー認証成功です!


## 参考
- [cognito-idp](https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/#)
- [motoserver](https://github.com/mergermarket/motoserver)
- [Amazon Cognito UserPoolによる認証機能をAWS CLIでサクッと作成する](https://dev.classmethod.jp/articles/quickly-create-an-authentication-function-with-amazon-cognito-userpool-with-the-aws-cli/)