AWS CognitoとAPI Gatewayを組み合わせて、スマホアプリで要ログインなAPIを作る

# やりたいこと
スマホアプリ(Android,iOSアプリ)内でAPI Gatewayにアクセスできるのを、あらかじめログインされたユーザに制限したい。

# やり方
1. Cognitoでログイン画面を作る。
2. ログイン時に取得したIdTokenを使ってAPIGatewayにアクセスする。
以上。

# Cognitoでログイン画面をつくる
## ユーザプールの作成
まず、Cognitoでユーザプールを作成します。
[この辺](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-user-identity-pools.html)を見れば大丈夫？(公式)
注意点としては、作成後に変更できない項目があるので、その辺気を付けないと後で泣きます。

## アプリの設定
ユーザプール作成時にアプリクライアントの設定をしていない場合は、コンソールの左ペインの「アプリクライアント」を選択し、「アプリクライアントの追加」を押下します。
![0001.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/2371d04a-33c9-b5cf-013c-e228d79373db.jpeg)



アプリクライアント名に任意のアプリ名称を設定し、「クライアントシークレットを生成」のチェックを外します。
![0002.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/06a33702-6b1f-4608-6560-b8881eb0d911.jpeg)
その他は、適当に設定して、「アプリクライアントを作成」を押下します。


アプリクライアントIDが表示されるので、メモしておきます。(後でも見れるので、忘れても大丈夫)
次に左ペインの「ドメイン名」を選択します。
![0003.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/5325b23e-46ec-f1ed-80ed-160a846d9879.jpeg)


ドメインのプレフィックスに任意の値を入力し「使用可能かチェック」を押下、使用できるなら「変更の保存」を押下します。
![0004.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/1c0ad950-8407-3645-08e4-06aaa02c1649.jpeg)

なお、ここで設定した、**https://<ドメインプレフィックス>.auth.xxxxx.amazoncognito.com**は、あとで貼付られるようにメモ帳なのにつなげた状態でコピっておくとよいと思います。


左ペインの「アプリクライアントの設定」を選択し、下記画像の用に設定します。
注意点としては、コールバックURL,サインアウトURLで、ここにログイン後、ログアウト後に遷移するURLを設定ます。
カンマ区切りで複数設定できるので、web用とアプリ用なんてこともできます。
なお、webの場合はhttpは不可でhttps必須となります。アプリの場合スキームを任意に指定できます。
また、許可されているOAuthフローは「Authorization code grant」と「Implicit grant」にチェックをつけます。
![0005.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/17e030be-5bcd-ac56-ee50-7fc8fa31fbe2.jpeg)
設定したら、「変更の保存」を押下します。

これでCognito側の設定は完了です。

# ログインする
## ログイン画面
ログインはwebブラウザから行います。
アプリの場合でもブラウザに飛ばしてログイン画面を表示します。
URLは、

```
https://<ドメインプレフィックス>.auth.xxxxx.amazoncognito.com/login?response_type=code&client_id=<アプリID>&redirect_uri=<コールバックURL>
```
となります。
ここにアクセスすると・・・以下のようなログイン画面が表示されます。
![0006.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/bfbd5592-cd1c-7365-e558-b6c5cf590896.jpeg)
ここでアカウント作成(Sign up)や、パスワード再発行なども行えます。

ログインに成功すると、コールバックURLで指定したURLに遷移します。
その際、URLの末尾に**?code=xxxxxxxxxx**のように認証コードが付与されます。
このコードを使って各種トークンを取得します。

## トークンの取得
トークンを取得するには、下記URLに**POST**でアクセスします。
```
https://<ドメインプレフィックス>.auth.xxxxx.amazoncognito.com/oauth2/token
```
**パラメータ**

|キー|値|
|:---|:---|
|grant_type|authorization_code|
|client_id|アプリID|
|redirect_uri|コールバックURL|
|code|認証コード|

成功すると、以下のようなJSONが返ってきます。

```JSON
{
    "id_token": "<Idトークン>",
    "access_token": "<アクセストークン>",
    "refresh_token": "<リフレッシュトークン>",
    "expires_in": 3600,
    "token_type": "Bearer"
}
```

APIGatewayにアクセスする時には、このうち&lt;Idトークン&gt;を使用します。
ただし、この&lt;Idトークン&gt;は有効期限が1時間しかありません。
なので、有効期限が切れた場合は<リフレッシュトークン>を使って&lt;Idトークン&gt;を再取得する必要があります。

## IDトークンの再発行
IDトークンを再発行するには、下記URLに**POST**でアクセスします。
```
https://<ドメインプレフィックス>.auth.xxxxx.amazoncognito.com/oauth2/token
```
**パラメータ**

|キー|値|
|:---|:---|
|grant_type|refresh_token|
|client_id|アプリID|
|refresh_token|<リフレッシュトークン>|

リフレッシュトークンもデフォルトあと30日で有効期限がきれるため、その場合は再度ログインして認証コードからやり直す必要があります。


# APIGatewayの設定
## オーソライザーの設定
APIGatewayのコンソールで、対象のリソースの「オーソライザー」を選択して「新しいオーソライザーの作成」を押下します。
![0007.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/b4d73ced-8b07-9eda-b7c2-06e312b01759.jpeg)


名前に任意の値、タイプは「Cognito」、Cognitoユーザープールには作成したユーザープールを選択します。
トークンのソースには、任意の値を設定します。(ここで設定した値をキーにして、APIにアクセスするときにヘッダにIdトークンを設定します)
![0008.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/457b20de-a9c2-808d-bd50-11cf0c200d55.jpeg)
「作成」を押下します。

結果が表示されるので【テスト」を押下します。
![0009.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/ecb3a13b-4e6a-f722-c738-59ae71fddab2.jpeg)


認証トークンに<Idトークン>を入力し、「テスト」を押下します。
![0010.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/3e35862a-f872-459e-e5a2-f13185922d74.jpeg)
問題なければレスポンスに色々ユーザ情報が表示されます。

## 認証設定
対象リソースのメソッドで「メソッドリクエスト」を押下します。
![0011.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/22845863-a254-f113-1a56-6540a9da083f.jpeg)

認証で、Cognitoユーザープールオーソライザーにある先ほど作成したオーソライザーを選択して、チェックマークを押下します。
※オーソライザーが表示されない場合、左ペインでいったん別のリソースを選択したり、コンソールを開きなおしたりすると表示されると思います。
![0012.jpg](https://qiita-image-store.s3.amazonaws.com/0/316857/e336315d-a914-e245-850c-49f09cc0b4a0.jpeg)


# APIアクセス
あとは、普通にAPIにアクセスする際にヘッダにIdトークンを設定すればOKです。
Idトークンを設定せずにアクセスすると、「401 Unauthorized」が返ってきます。

# その他
基本的な部分のみですが、このままだとセキュリティ的には弱い部分もあるので下記公式ドキュメントを参照するとよいと思います。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-userpools-server-contract-reference.html

また、FacebookやGoogleのアカウントでのログインも可能です。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-user-pools-social-idp.html