Cognito User Pools x ログイン認証 x API認証

# はじめに
Cognito User Poolsを利用したログイン認証を行い、
API認証(Cognito ユーザープールオーソライザー)をかけているAPI Gateway上のAPIを叩くサンプルを作成しました。

サンプルはReactでの作成です。

# 前提（私の環境）
Windows 10 Pro (64bit)
[Git for Windows](https://git-for-windows.github.io/) (Git Bash)
[Node.js](https://nodejs.org/ja/) (v6.9.4 LTS / Windows(x64))
[AWS](https://aws.amazon.com/jp/) (アカウント作成済)

# Cognito User Poolの作成
サービスから「Cognito」を選択し、「Manage your User Pools」から管理画面へ移動し、CognitoのUser Poolを作成します。
Pool nameを入力し、「Review defaults」で設定をいくつか修正します。

## Password policy
サンプルなので少し緩くしました。必要に応じて。
uppercase letters, lowercase letters, numbers

## Apps
認証用のクライアントアプリを追加します。
「Add an app」から「App name」を指定してアプリを追加します。
「Generate client secret」はJavaScriptからの利用時に
シークレットキーを使う設定だとエラーになってしまうのでチェックを外しておきます。

[AWS Cognito User Pools のサインアップ時に NotAuthorizedException が出る (JavaScript)](http://qiita.com/noobar/items/6615501b035e47792227)

## ユーザの追加
User Poolを作成したら「Users and groups」メニューからユーザを追加します。
設定はこんな感じです。パスワードは後で使うので控えておきます。
![CreateUser2.png](https://qiita-image-store.s3.amazonaws.com/0/138821/cc96ef68-c9b8-5f56-5bef-a2363c148f08.png)

# Cognito Identity Pool の作成
次にIdentity Poolを作成します。
サービスから「Cognito」を選択し、「Manage Federated Identities」から
管理画面へ移動し、「Create new identity pool」から作成します。

## Authentication providers
ここの「Cognito」タブに先程作成したUser Poolの
「User Pool ID」と「App Client ID」を入力して追加します。

## ロールのアサイン
「Create Pool」で作成すると「ロール」のアサインについて聞かれるので
ここではデフォルトの「新しいIAM ロールの作成」で作成します。

# Lambda関数の作成
次にアクセスするAPIで利用するLambda関数を作成します。
サービスから「Lambda」を選択し、「Create a Lambda function」から作成します。

## Select blueprint
「Blank Function」を選択します。

## Configure triggers
そのまま「Next」

## Configure function
- Name：お好みで
- Runtime：Node.js 4.3

### Lambda function code
少し修正します。

```diff
exports.handler = (event, context, callback) => {
    // TODO implement
-   callback(null, 'Hello from Lambda');
+   context.done(null, {message: "Hello API"});
};
```

### Lambda function handler and role
- Handler：index.handler
- Role：Create new role
- Role name：お好みで
- Policy templates：Simple Microservice permission

あとはそのままで作成します。

# APIの作成
次にアクセスするAPIを作成します。
サービスから「API Gateway」を選択し、「APIの作成」から名前を付けて作成します。

## オーソライザーの作成
作成したAPIの「オーソライザー」を選択し「作成」プルダウンから
「Cognito ユーザープールオーソライザー」を選択します。
![Authorizer.png](https://qiita-image-store.s3.amazonaws.com/0/138821/f4d91fd0-4402-c82d-be1c-29f1740acffa.png)

- Cognito リージョン：先程作成したCognito User Poolのリージョンを指定します。
- Cognito ユーザープール：同様に先程作成したCognito User Poolの名前を指定します。

あとはそのままで作成します。

## メソッドの作成
「アクション」プルダウンから「メソッドの作成」を選択し「GET」メソッドを作成します。
- 統合タイプ：Lambda関数
- Lambdaリージョン：お好み
- Lambda関数：作成したLambda関数名

作成時に権限を与えるか聞かれるので、与えます。

### メソッドリクエストの設定
作成したメソッドの「メソッドリクエスト」から認証設定を行います。
認証に作成した「Cognito ユーザープールオーソライザー」を指定します。

## CORSの有効化
JavaScriptのアプリケーションからアクセスするので、
「アクション」プルダウンから「CORSの有効化」を選択して有効化しておきます。
![EnableCORS.png](https://qiita-image-store.s3.amazonaws.com/0/138821/7235c179-9b3f-c713-f960-76e21bc1794e.png)

設定はそのままで「CORS を有効にして既存の CORS ヘッダーを置換」で有効化します。

## API のデプロイ
最後に「アクション」プルダウンから「APIのデプロイ」を選択してAPIをデプロイします。
![DeployAPI.png](https://qiita-image-store.s3.amazonaws.com/0/138821/90c1bc67-1309-bc82-b767-0cb1d625ae40.png)

- デプロイされるステージ：[新しいステージ]
- ステージ名：prod

これでデプロイまで完了しました。
この時点でデプロイされたAPIにGETアクセスすると「{"message":"Unauthorized"}」が返されるはずです。

# 認証 & API実行 アプリケーション
こちらはソースを以下にコミットしてあります。
[DaisukeOtaka/cognito-auth-example](https://github.com/DaisukeOtaka/cognito-auth-example)

これまで設定してきた情報を環境変数として指定し
アプリケーションを起動します。

- REGION: AWS Cognito Region (Cognitoのリージョン)
- COGNITO_IDENTITY_POOL_ID: Cognito Identity Pool ID (作成したIdentity PoolのID)
- COGNITO_USER_POOL_ID: User Pool ID (作成したUser PoolのID)
- COGNITO_APP_CLIENT_ID: App Client ID (作成したUser Poolで追加したApp Client ID)
- INVOKE_URL: AWS API Gateway Invoke URL (作成したAPI GatewayでデプロイしたURL)
- DEFAULT_USERNAME: Default Username for Sign In (User Poolに追加したユーザのユーザ名)
- DEFAULT_PASSWORD: Default Password for Sign In (User Poolに追加したユーザの一時パスワード)

起動時に環境変数を指定するには、例えばPORTを指定する場合には↓みたいな感じになります。
```bash
$ PORT=5001 npm start
```

実行するとこんな感じでログインとAPI実行ができます。
![Sign In](https://raw.githubusercontent.com/DaisukeOtaka/cognito-auth-example/images/images/SignIn.png)

![My Page](https://raw.githubusercontent.com/DaisukeOtaka/cognito-auth-example/images/images/MyPage.png)

# 参考
- [AWS SDK for JavaScriptでCognito User Poolsを使ったログイン画面を作ってみた](http://dev.classmethod.jp/cloud/aws/login-form-by-using-aws-sdk-for-javascript/)

- [Serverless AWS構成でセキュアなSPAを目指す](http://www.slideshare.net/masayuki-kato/serverless-awsspa)

- [Node.js から API Gateway を簡単に使えるパッケージ作りました](http://qiita.com/kndt84/items/25445998a7c372864cde)