Next.jsを使ってAWS Cognitoユーザープールにサインアップ・サインインリクエストしてみる【その①】

# はじめに
普段のお仕事ではフロントエンドを担当していて、主にNext.js × TypeScriptを使用しています
AWS資格の勉強をしているものの、AWSに触れる機会がなく
気になっていたAWS Cognitoを使って遊んでみました

2回に分けて記事を書いていきます！

## AWS Cognitoとは？
AWSが提供する、Webアプリとモバイルアプリ用のユーザー認証サービスです
Cognitoには主に2つの機能があります

- <ins>**ユーザープール**</ins>
    - ユーザーのサインアップやサインインができる
- <ins>**アイデンティティプール**</ins>
    - ユーザにアクセス許可を割り当てたり、外部サービスと連携してサインインできる

今回はサインアップ（ユーザーの作成）が行いたいので、ユーザープールを使用します

## Cognito側の準備
早速ユーザープールを作成していきます

### ①サインインエクスペリエンスを設定
どの要素でユーザーがサインインできるかを決めます
今回は**ユーザー名**、**Eメール**両方からサインインできるようにしてみたいと思いますので、それぞれにチェックを入れてください
ユーザー名の要件も両方ともチェックを入れました

OKだったら「次へ」を押しましょう

![97532E09-5E04-4F33-B6CE-F285948AD1E5_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1156536/d73951fe-30cc-6f5b-976f-95ea7ed882dd.jpeg)


### ②セキュリティ要件を設定

MFAは使用しないので、「MFAなし」だけを選んで、他は全てデフォルトにしました

OKだったら「次へ」を押しましょう

### ③サインアップエクスペリエンスを設定
どの要素でユーザーが作成（サインアップ）できるかを決めます
「必須の属性」セクションで、emailに加え、「追加の必須属性」から「name」を選択しました
その他は全てデフォルトの設定のままです

OKだったら「次へ」を押しましょう

![C09C2994-F09E-411D-9987-C6FDF5A51A75_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1156536/0bd34a06-9751-079d-ed65-78d8bd6bffc4.jpeg)

### ④メッセージ配信を設定
Cognitoからメッセージを送信す手段を選択します

これを設定すると、ユーザー作成時に確認メールとかが飛んでくるようになります
私は「Cognito で E メールを送信」を選択し、「返信先 Eメールアドレス」に自分のemailを入力しました

OKだったら「次へ」を押しましょう

![スクリーンショット 2023-07-28 18.25.52（2）.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1156536/b445a50d-1a32-98e7-4196-07209efa4d0f.jpeg)

### ⑤アプリケーションを統合
アプリと連携する大事な設定です
「ユーザープール名」「アプリケーションクライアント名」を入力し、「**クライアントシークレットを生成しない**」を選択しました
その他は全てデフォルトの設定です
**※パブリッククライアントと秘密クライアントについては筆者も勉強中です...（にわか知識お許しください）**

OKだったら「次へ」を押し、確認して問題なければ作成しましょう！

さて、ここからはNext.js側の準備です！

## Next.js側の準備
Next.jsからCognitoへリクエストをする方法はいろんな記事があり、最初はどれをすればいいのか全然分からず...（NextAuthとか使ってみたいけど）

と思っていたところ、[amazon-cognito-identity-js](https://www.npmjs.com/package/amazon-cognito-identity-js)というSDKライブラリを使用するのが一番手っ取り早く簡単そうだったので、今回使用させていただきました

### ①パッケージを追加する
使用しているパッケージ管理に合わせて、以下のコマンドでインストールしてください

```
npm i amazon-cognito-identity-js
```
もしくは
```
yarn add amazon-cognito-identity-js
```

### ②環境変数にCognitoの情報を保存する
Cognitoにアクセスするためには、以下の二つが必要です
- ユーザープールID
- クライアントID（アプリケーションクライアントのことです）

クライアントIDは「アプリケーションの統合」タブのアプリケーションクライアントから取得できます

「.env.local」ファイルを作成して、2つのIDを保存しましょう
**※環境変数はちゃんと.gitignoreしましょうね**

私は以下のような命名で保存しました

```
NEXT_PUBLIC_COGNITO_USER_POOL_ID=ユーザープールID
NEXT_PUBLIC_COGNITO_CLIENT_ID=クライアントID
```

### ③ユーザー作成（サインアップ）リクエストの関数を作成する

Cognitoにリクエストする用の関数を作成します

```
import {
  CognitoUser,
  AuthenticationDetails,
  CognitoUserPool,
  CognitoUserAttribute,
} from 'amazon-cognito-identity-js';

const poolData = {
  UserPoolId: process.env.NEXT_PUBLIC_COGNITO_USER_POOL_ID ?? '', // 環境変数はundefined許容するので「?? ''」を追加する
  ClientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID ?? '',
};

const signUp = (
    userName: string,
    email: string,
    password: string
  ): Promise<void> => {
    // poolDataを元にユーザープールを作成
    const userPool = new CognitoUserPool(poolData);

    // ユーザー作成に必要な値の配列
    const attributeList: CognitoUserAttribute[] = [];

    // ユーザー名
    const nameData = {
      Name: 'name',
      Value: userName,
    };

    // Eメール
    const emailData = {
      Name: 'email',
      Value: email,
    };

    const attributeName = new CognitoUserAttribute(nameData);
    const attributeEmail = new CognitoUserAttribute(emailData);

    attributeList.push(attributeName);
    attributeList.push(attributeEmail);
    attributeList.push(attributePhoneNumber);

    // SDKの関数が非同期じゃなかったので、非同期になるようにnew Promiseにする
    return new Promise<void>((resolve, reject) =>
      userPool.signUp(userName, password, attributeList, [], (err, result) => {
        if (err) {
          console.error('err : ', err);
          reject(err);
          return;
        }
        const cognitoUser = result?.user;
        if (typeof cognitoUser === 'undefined') {
          console.error('user undefined : ', cognitoUser);
          reject(cognitoUser);
          return;
        }
        resolve();
      })
    );
  };
```

ここまでを経て、Cognitoにユーザーを作成することまではできます！

## 疲れたので今日はここまで
次の記事ではサインアップ後、トークンを発行してどうやってログインするかを解説していきたいと思います！

不慣れな点もあるため間違っていることがあると思うので、もし何か間違っていた場合はコメントいただけると幸いです！

次回の記事もお楽しみに
ではまた！