Amazon Cognito を利用した認証と認可の流れ - 概要の理解 編

# 概要

![image.png](https://qiita-image-store.s3.amazonaws.com/0/316045/f46b39e8-1666-f62c-a187-249e6f0cb8ca.png)

当記事は、Amazon Cognito を利用した認証と認可の流れを実装するうえで、自分が概要の理解に努めた記録を纏めたものになります。また、上記の図は [公式の説明図](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/what-is-amazon-cognito.html) を **自分が理解しやすいように加筆、修正をさせていただいた** ものになります。

# Amazon Cognito の機能
Amazon Cognito は大きく分けると **User pool**, **Identity pool**, **Sync** の3つの機能から構成されています。 **Sync** については、当記事の認証と認可の流れでは利用しないため調査を行っていません。

## User pool について
**User pool** は、ユーザーに関連する情報を格納し保持しつづける機能や、ユーザーのサインアップ、サインイン ( Google、Facebook、Amazon 経由などにも対応しています) 機能等を提供してくれています。**「認証と認可の流れ」** では **認証** を担ってくれる機能だと理解しています。

### 参考資料
- [公式ドキュメント - Amazon Cognito ユーザープール](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-user-identity-pools.html)

## Identity pool について
**Identity pool** は、**Credentials** を生成してくれます。この  **Credentials** の実体は、 **Identity pool** に設定された **IAM Role** を、**AWS STS(Security Token Service)** がユーザーのリクエスト毎に発行した **IAM Role と同等の権限を持った一時的な認証情報** を指します。

**Identity pool** の AWS 公式ドキュメント中には **認可** という言葉は一度もでてこないのですが、これは **IAM Role** の役割を思い出すと合点がいきました。 **IAM Role** は、AWS のサービスなど認可されたエンティティに割り当てるために用意されたものです。つまり、それを払い出す **Identity pool** (厳密には **AWS STS**)は**「認証と認可の流れ」**では **認可** を担ってくれる機能になると理解しています。

文章で纏めているだけでは理解するのが難しかったので、**Identity pool** で行われることに焦点をあて、下記の図を作成して理解に努めました。AWS 公式の図ではないので正確なものではありませんが結果として理解に繋がりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/316045/fa2f4868-32c0-4fdf-8531-3393e0cd5946.png)

### 参考資料
- [公式ドキュメント - AWS Security Token Service](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp.html)
- [公式ドキュメント - Amazon Cognito ID プール](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-identity.html)
- [クラスメソッド株式会社 - 都元様 - IAMロール徹底理解 〜 AssumeRoleの正体](https://dev.classmethod.jp/cloud/aws/iam-role-and-assumerole/)

# 処理の説明

## 1. 認証処理
**User pool** に対し認証処理を実行します。これは新規ユーザー情報のサインアップであったり、既存ユーザーの情報を用いたサインインにあたる処理になります。認証処理が成功すると、 **User pool** から下記のレスポンスが返却されます。

```jsonnet
{
   "AuthenticationResult": { 
      "AccessToken": "string",
      "ExpiresIn": number,
      "IdToken": "string",
      "NewDeviceMetadata": { 
         "DeviceGroupKey": "string",
         "DeviceKey": "string"
      },
      "RefreshToken": "string",
      "TokenType": "string"
   },
   "ChallengeName": "string",
   "ChallengeParameters": { 
      "string" : "string" 
   },
   "Session": "string"
}
```
**User pool** から返却されたレスポンスには、以下の **Token** が含まれています。
### IdToken
認証されたユーザーに関するクレーム([OIDC 標準クレーム](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims))が含まれています。 主に **Identity pool** に対し AWS リソースに対する **Credentials** を要求する場合に用いられます。有効期限は、ユーザーが認証に成功してから 1 時間後に有効期限切れになります。失効した **IdToken** を利用することはできません。

### AccessToken
**IdToken** 同様に、認証されたユーザーに関するクレーム(id情報をのぞく)が含まれています。主に **User pool** 内のユーザー属性を追加、変更、または削除する場合に利用します。有効期限は、ユーザーが認証に成功してから 1 時間後に有効期限切れになります。失効した **AccessToken** を利用することはできません。**RefreshToken** を用いて再発行するか認証を再試行する必要があります。

### RefreshToken
新規 **AccessToken**, **IdToken** の取得時に利用します。この時、**RefreshToken** は再生成されません。**RefreshToken** が失効した場合は、再度、認証を試行する必要があります。 有効期限は、デフォルトではユーザーが認証に成功してから 30 日後に有効期限が切れます。**RefreshToken** の有効期限は 1 ～ 3650(日) の範囲で任意の値に設定可能です。

### IdToken と AccessToken についての補足
**IdToken**, **AccessToken** は [JWT(Json Web Tokens)](https://jwt.io/introduction/) 形式で格納されています。JWT は2者間でやりとりされる軽量なある主体に関するひと纏まりの情報で、情報のセットを JSON Object として文字列で表現して、情報に対するデジタル署名や MAC と暗号化の両方が可能になるというものです。

アプリケーションの外部で **AccessToken** と **IdToken** を利用する場合、JWT が悪意あるものによって変更されている可能性があることを前提にして **必ず Token を承認する前に Token の署名を確認し、改ざんが行われていないかを検証しましょう。**

### 参考資料
- [公式ドキュメント - User pool Tokens の使用](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html) 
- [公式ドキュメント - JSON Web Tokens の検証](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html) 
- [JSON Web Token (JWT)
draft-ietf-oauth-json-web-token-11](https://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.html)

## 2. 認可処理
認証処理で取得した Token 中に含まれる **IdToken** を利用して、AWS リソースに対する **Credentials** を要求します。このときに取得される **Credentials** の実体は、上記の **「Identity pool について」** の項でも纏めたとおり、**Identity pool** に設定された **IAM Role と同等の権限を持った一時的な認証情報** を指します。

デフォルトでは、 **Credentials** が払い出されてから 1 時間後に有効期限が切れます。 **Credentials** の有効期限は 3,600 (1 時間) ~ 43,200(12 時間) 秒の範囲であれば、任意の値に **IAM Role** の設定から可能です。

認可処理に成功すると、**Identity pool** から下記のレスポンスが返却されます。この中に含まれる **Credentials** を利用して、署名付きのリクエストを作成します。

```jsonnet
{
   "Credentials": { 
      "AccessKeyId": "string",
      "Expiration": number,
      "SecretKey": "string",
      "SessionToken": "string"
   },
   "IdentityId": "string"
}
```

### 参考資料
- [IAM とは](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/introduction.html) 
- [一時的セキュリティ認証情報](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp.html) 

## 3. 署名付きリクエスト
最後に、取得した **Credentials** を利用して署名付きリクエストを作成します。署名付きリクエストの作成手順は AWS 公式に記載されていますが、各種言語毎の署名付きリクエストを簡単に作成できるように AWS が SDK を用意してくれています。SDK が利用できない場合をのぞいて SDK を積極的に利用しましょう。

### 参考資料
- [署名バージョン4 署名プロセス](https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-4.html) 
- [各種SDK](https://aws.amazon.com/jp/getting-started/tools-sdks/) 

# 次回
下記のいずれかになると思います。

- もう少し Amazon Cognito について理解を深める
- 大好きな PHP で Amazon Cognito を利用した認証と認可の流れを実装