OAuthとOpenIDConnectを何となく理解する

## 目次
- [0. 認証と認可](#0-認証と認可)
- [1. OAuth2.0](#1-oauth20)
  - [1-1. 構成するエンティティ](#1-1-構成するエンティティ)
  - [1-2. 処理フローについて](#1-2-処理フローについて)
    - [1-2-1. 認可コードフロー(Authorization Grant Flow)](#1-2-1-認可コードフローauthorization-grant-flow)
    - [1-2-2. インプリシットフロー(Implicit Flow)](#1-2-2-インプリシットフローimplicit-flow)
    - [1-2-3. リソースオーナーパスワードクレデンシャルフロー(Resource Owner Password Credentials Flow)](#1-2-3-リソースオーナーパスワードクレデンシャルフローresource-owner-password-credentials-flow)
    -  [1-2-4. クライアントクレデンシャルフロー(Client Credentials Flow)](#1-2-4-クライアントクレデンシャルフローclient-credentials-flow)
    - [1-2-5. 処理フローまとめ](#1-2-5-処理フローまとめ)
- [2. OAuth認証とその脆弱性](#2-oauth認証とその脆弱性)
- [3. OpenIDConnect](#3-openidconnect)
  - [3-1. 構成するエンティティ](#3-1-構成するエンティティ)
  - [3-2. `response_type`パラメータの取りうる値](#3-2-response_typeパラメータの取りうる値)
  - [3-3. 処理フローについて](#3-3-処理フローについて)

## 0. 認証と認可
### 認証 （Authorization）
**誰であるか**の証明です。
指紋認証とか顔認証とか。

### 認可 （Authentication）
権限の付与です。**誰が** **誰に** **何の権限を** 与えるかが明確にされる必要があります。
例えば、あるファイルサーバの「管理者が」「新入社員に」「共通フォルダへのフルアクセス権を」与えるみたいなことを認可と呼びます。

## 1. OAuth2.0
OAuth2.0は**認可**のためのオープンスタンダードなプロトコルです
仕様は[RFC6749](https://datatracker.ietf.org/doc/html/rfc6749), [RFC6750](https://datatracker.ietf.org/doc/html/rfc6750)で定められています。

そもそもどういう時にOAuth2.0を使いたいのかというと、
**あるサービスAから他のサービスBのリソースにアクセスしたい時**です。

サービスA->サービスBのアクセスにサービスBのアクセストークンが必要という状況を仮定します。
この時、OAuth2.0は
**サービスAに対してサービスBのアクセストークンを発行する(アクセス権限を付与する)ためのプロトコル**
ということができます。

## 1-1. 構成するエンティティ
OAuth2.0には以下の3つのエンティティが登場します。

- **リソースサーバ (resource server)**
    - アクセスしたいリソースを有するサーバ
    - サービスBのこと
- **クライアント (client)**
    - リソースサーバにアクセスする側
    - サービスAのこと
- **認可サーバ (authorization server)**
    - クライアントに認可ページの提供やアクセストークンの発行を行う機構のこと
    - 認可のためのエンドポイントやトークン発行のためのエンドポイントなど、さまざまなエンドポイントを構えている

## 1-2. 処理フローについて
認可サーバがクライアントにアクセストークンを発行するまでの処理フローが4つ定められています。

https://datatracker.ietf.org/doc/html/rfc6749#section-1.3

それぞれのフローの詳細については以下の記事が大変参考になります。

https://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f

本記事では概要のみ触れておくことにします。

### 1-2-1. 認可コードフロー(Authorization Grant Flow)
認可決定エンドポイントはクライアントに直接アクセストークンを返すのではなく**認可コード**なるコードを返します。
クライアントがアクセストークンを取得するには、認可コードをトークンエンドポイントに提示する必要があります。

### 1-2-2. インプリシットフロー（Implicit Flow）
認可決定エンドポイントはクライアントに直接アクセストークンを返します。
"Implicit"とは、"暗黙的"という意味です。[^1]

### 1-2-3. リソースオーナーパスワードクレデンシャルフロー（Resource Owner Password Credentials Flow）
認可サーバは認可エンドポイントを構えておらず、リダイレクトの認可画面もありません。
その代わりにクライアントはリソースサーバのID/PWを保持する必要があり、それらをトークンエンドポイントに提示する必要があります。

### 1-2-4. クライアントクレデンシャルフロー（Client Credentials Flow）
クライアントがリソースサーバから事前に取得したクレデンシャルを使ってアクセストークンを取得します。
AWSで言うところの、(事前に取得しておいた)アクセスキーとシークレットアクセスキーを使ってcli操作するみたいなイメージでしょうか。
このフローに関しては、以下の記事がわかりやすかったです。

https://tech-lab.sios.jp/archives/25470#i-4

## 1-2-5. 処理フローまとめ
上記4つの処理フローは、使用するエンドポイントや登場するトークンに違いがあります。
それらをまとめると以下の表になります。

|フロー|認可エンドポイント|認可決定エンドポイント|トークンエンドポイント|認可コード|備考|
|:--|:--|:--|:--|:--|:--|
|認可コード|O|O|O|O|認可コードを用いてアクセストークンの発行を許可する|
|インプリシット|O|O|X|X|トークンエンドポイントを使用せず、認可クレデンシャルが通ればアクセストークンが直接もらえる|
|リソースオーナーパスワードクレデンシャル|X|X|O|X|認可情報の入力が不要なので認可エンドポイントを使用しない。リソースサーバのクレデンシャルでアクセストークンを取得。|
|クライアントクレデンシャル|X|X|O|X|認可情報の入力が不要なので認可エンドポイントを使用しない。事前に取得したクレデンシャルでアクセストークンを取得。|

## 2. OAuth認証とその脆弱性
OpenIDConnectの説明に入る前に、**OAuth認証**なる認証手順について説明します。認可じゃなくて、**認証**です。

上述の通り、OAuthはアクセストークンを用いた認可のためのプロトコルです。
が、その過程では認証も同時に行われています。
つまり、OAuthは認可のためのプロトコルでありながら、認証にも使えてしまうということになります。
このOAuthの特徴を利用して、**本来認可のプロトコルであるOAuthを使って認証を"済ませてしまう"ような認証手法**を**OAuth認証**などと呼んだりします。

ただし、OAuth認証には重大なセキュリティーホールを孕んでいることが知られています。
以下の記事が有名らしいです。

http://www.thread-safe.com/2012/01/problem-with-oauth-for-authentication.html

## 3. OpenIDConnect
OAuth認証の脆弱性を踏まえ、OAuth2.0の拡張として登場したのがOpenIDConnect(OIDC)です。つまりOIDCは**認証のためのプロトコル**であり、認可のためのプロトコルであるOAuthとは若干目的が異なります。

特徴としては、**IDトークン**なるJWTでクレデンシャルを管理する点にあります。
IDトークンについては以下で定義されています。

https://openid.net/specs/openid-connect-core-1_0.html#IDToken

つまりOIDCとは、
**OAuthの拡張として、IDトークンもレスポンスできるように設計されたプロトコル**
ということができます。

## 3-1. 構成するエンティティ
OAuthの拡張になるので、基本的にはOAuthと変わらないのですが、OIDCの場合、認可サーバは **IDプロバイダ(IdP)** と呼ばれます。
登場するエンティティは以下の2つです。

- **クライアント**
- **IdP**

認可サーバがIdPという呼び方にかわりましたが、基本的な機能としてはOAuthに登場した認可サーバと変わりません。変わる点はむしろクライアント側にあって、クライアントは認可エンドポイントへのリクエストに含まれる`scope`パラメータに`openid`を指定した上で、`response_type`パラメータに特定の値を追加することでOIDCを利用できます。

## 3-2. `response_type`パラメータの取りうる値
種類としては、以下の4つがあります。

- **code**
  認可コードのリクエストを意味します
- **token**
  アクセストークンのリクエストを意味します
- **id_token**
  IDトークンのリクエストを意味します
- **none**
  何も(認可トークンも、アクセストークンも、IDトークンも)リクエストしないことを意味します

一点留意すべきなのは、上記のリクエストは**認可エンドポイント**へのリクエストであるという点です。
つまり、例えば`response_type`に`code`を指定した場合、あくまでも**認可エンドポイントは認可コードのみレスポンスする**という意味になります。その他のトークンはトークンエンドポイントからレスポンスされ、最終的にクライアントは認可コードもアクセストークンもIDトークンも取得できます。

## 3-3. 処理フローについて
OIDCの処理フローは前述した`response_type`の値の組み合わせによって複数あります。
フローの詳細については、以下の記事が大変参考になります。
先ほどのOAuth処理フローの解説記事と同じ方が執筆されています。神に感謝。。

https://qiita.com/TakahikoKawasaki/items/4ee9b55db9f7ef352b47

詳細は上記記事に丸投げするのですが、要約すると
- リクエストの`scope`パラメータの値によって、OAuthのリクエストなのかOIDCのリクエストなのかが識別される
- リクエストの`response_type`パラメータの値によって、使用するエンドポイントと最終的なレスポンスが異なる

という感じでしょうか。

## 最後に
OAuthとOIDC、よく聞くけどいつかちゃんと調べないとな〜と思ってましたがやっと"何となくわかる"ところまでは理解できたかなという感じです
処理フローのところ完全に他記事に任せっきりでしたが、実際めちゃくちゃ参考になったのでその記事だけでもぜひご参考ください！

次はOAuth、OIDCとAWS Cognitoの関連について調べようかな〜と思っております！

## 参考
https://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f

https://tech-lab.sios.jp/archives/25470#i-4

http://www.thread-safe.com/2012/01/problem-with-oauth-for-authentication.html

https://qiita.com/TakahikoKawasaki/items/4ee9b55db9f7ef352b47

[^1]:認可トークンは暗黙して(トークンエンドポイントもスキップしちゃって)ええやろ的な意味かなと理解してます