【永久保存版】OAuth 2.0 / OpenID Connect シーケンスまとめ


こんにちは、[kura](https://twitter.com/kura_lab)です。

この記事は[Digital Identity技術勉強会 #iddance のアドベントカレンダー](https://qiita.com/advent-calendar/2021/iddance)の12日目の記事です。

開発チームを離れてプロジェクトやサービスのマネジメントが中心の業務になっており、コーディングを全然しなくなったのですが、上流工程でシーケンス図はよく書くため、自身の作業効率を上げる意味も含めて今回はOAuth 2.0やOpenID Connectのシーケンス図をまとめようと思います。
画像だけでなくPlantUMLのコードも掲載しておくので、みなさんにも活用いただけたらと思います。

# PlantUMLについて
PlantUMLはクラス図やシーケンス図がかけるオープンソースの描画ツールです。Qiitaにも記事をまとめてくださっている方はたくさんいるので詳しい情報は検索してみてください。
筆者は以下のあたりを参考にVSCodeとの組み合わせで作成しています。PlantUMLの環境を作っていない方は参考にしてみてください。

https://qiita.com/couzie/items/9dedb834c5aff09ea7b2

PlantUMLの構文については以下を参考にしてカスタマイズしてもらえたらと思います。

https://plantuml.com/ja/sequence-diagram

# OAuth 2.0

[RFC 6749](https://datatracker.ietf.org/doc/rfc6749/)に定義されているOAuth 2.0のシーケンス図からまとめていきます。
フローの解説はAuthleteの[@TakahikoKawasaki](https://qiita.com/TakahikoKawasaki)さんの解説を参考にするとよいと思います。

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

## OAuth 2.0 Abstract Protocol Flow

まずは[RFC 6749](https://datatracker.ietf.org/doc/rfc6749/)のはじめの概要にも登場する概念的なシーケンス図です。
シンプルですね。上流工程での資料ではこのレベルでもよいかもしれません。

```plantuml
@startuml OAuth 2.0 Abstract Protocol Flow
autonumber
participant Client as C
actor "Resource \nOwner" as RO
participant "Authorization \nServer" as AS
participant "Resource \nServer" as RS

C -> RO: Authorization Request
RO -> C: Authorization Grant
C -> AS: Authorization Grant
AS -> C: Access Token
C -> RS: Access Token
RS -> C: Protected Resource
@enduml
```

<details><summary>OAuth 2.0 Abstract Protocol Flow（PlantUMLソースコード）</summary><div>

```
@startuml OAuth 2.0 Abstract Protocol Flow
autonumber
participant Client as C
actor "Resource \nOwner" as RO
participant "Authorization \nServer" as AS
participant "Resource \nServer" as RS

C -> RO: Authorization Request
RO -> C: Authorization Grant
C -> AS: Authorization Grant
AS -> C: Access Token
C -> RS: Access Token
RS -> C: Protected Resource
@enduml
```
</div></details>

## OAuth 2.0 Authorization Code Grant

OAuth 2.0のGrant Typeの中でも最も利用されるのがAuthorization Code Grantです。
Authorization Codeを発行し、Access Tokenを取得し、Resource Serverへアクセスするまでの最低限のフローを記載しています。

※ Grant Typeは4つのタイプが存在しますが、OAuth 2.0の後継にあたる策定中の[OAuth 2.1](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/)ではImplicit GrantおよびResoiurce Owner Password Credential Grantは除外されているため今回は掲載しません。

```plantuml
@startuml OAuth 2.0 Authorization Code Grant
autonumber
actor "Resource\nOwner" as RO
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource\nServer" as RS

RO -> C:
C -> UA: Authorization Request\nClient Identifier & Redirection URI\n& State
UA -> AS:
AS -> UA: User authenticates & grants
UA -> RO:
RO -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code & Redirection URI
AS -> C: Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource
@enduml
```

<details>
<summary>OAuth 2.0 Authorization Code Grant（PlantUMLソースコード）</summary>
<div>

```
@startuml OAuth 2.0 Authorization Code Grant
autonumber
actor "Resource\nOwner" as RO
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource\nServer" as RS

RO -> C:
C -> UA: Authorization Request\nClient Identifier & Redirection URI\n& State
UA -> AS:
AS -> UA: User authenticates & grants
UA -> RO:
RO -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code & Redirection URI
AS -> C: Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource
@enduml
```
</div>
</details>

## OAuth 2.0 Authorization Code Grant with Refresh Token

次はAuthorization Code GrantでオプションになっているRefresh Tokenの発行とAccess Tokenの更新を含めたシーケンス図になります。

```plantuml
@startuml OAuth 2.0 Authorization Code Grant with Refresh Token
autonumber
actor "Resource\nOwner" as RO
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource\nServer" as RS

RO -> C:
C -> UA: Authorization Request\nClient Identifier & Redirection URI\n& State
UA -> AS:
AS -> UA: User authenticates & grants
UA -> RO:
RO -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code & Redirection URI
AS -> C: Access Token & Refresh Token

alt Valid Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource

else Refreshing an Expired Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Invalid Token Error
C -> AS: New Access Token Request\nRefresh Token
AS -> C: Access Token & Optional Refresh Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource
end
@enduml
```

<details>
<summary>OAuth 2.0 Authorization Code Grant with Refresh Token（PlantUMLソースコード）</summary>
<div>

```
@startuml OAuth 2.0 Authorization Code Grant with Refresh Token
autonumber
actor "Resource\nOwner" as RO
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource\nServer" as RS

RO -> C:
C -> UA: Authorization Request\nClient Identifier & Redirection URI\n& State
UA -> AS:
AS -> UA: User authenticates & grants
UA -> RO:
RO -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code & Redirection URI
AS -> C: Access Token & Refresh Token

alt Valid Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource

else Refreshing an Expired Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Invalid Token Error
C -> AS: New Access Token Request\nRefresh Token
AS -> C: Access Token & Optional Refresh Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource
end
@enduml
```
</div>
</details>

## OAuth 2.0 Client Credentials Grant

ユーザーとのインタラクションを伴わないClientとAuthorization Serverの2者間でやり取りされるClient Crendetial Grantもニーズが高いため記載しておきます。

```plantuml
@startuml OAuth 2.0 Client Credentials Grant
autonumber
participant Client as C
participant "Authorization\nServer" as AS
participant "Resource\nServer" as RS

C -> AS: Access Token Request\nClient Authentication
AS -> C: Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource
@enduml
```

<details>
<summary>OAuth 2.0 Client Credentials Grant（PlantUMLソースコード）</summary>
<div>

```
@startuml OAuth 2.0 Client Credentials Grant
autonumber
participant Client as C
participant "Authorization\nServer" as AS
participant "Resource\nServer" as RS

C -> AS: Access Token Request\nClient Authentication
AS -> C: Access Token
C -> RS: Protected Resource Request\nAccess Token
RS -> C: Protected Resource
@enduml
```
</div>
</details>

# OpenID Connect

[OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)に定義されているOpenID Connectのシーケンス図もまとめます。
こちらも[@TakahikoKawasaki](https://qiita.com/TakahikoKawasaki)さんの解説を参考にしてもらえたらよいと思います。

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

2015年にまとめた筆者のシーケンス図の資料も13万回以上アクセスされており、みなさんのお役に立ててそうで何よりです。よかったらこちらも参考にしてみてください。

https://www.slideshare.net/kura_lab/openid-connect-id

## OpenID Connect Abstract Protocol Flow

それではOpenID Connectのシーケンス図をまとめていきます。はじめは[OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)のOverviewに記載されている概念的なフローになります。

こちらもOAuth 2.0のAbstract Protocol Flowと同様にシンプルですね。シーケンス図に登場する役割はOAuth 2.0とほとんど同じですが、OAuth 2.0の定義とは名称が異なるので資料を作成する際には注意が必要です。

```plantuml
@startuml OpenID Connect Abstract Protocol Flow
autonumber
participant "RP\n(Client)" as RP
actor "End-User" as EU
participant "OP\n(OpenID Provider)" as OP

RP -> OP: Authentication Request
OP -> EU: Authentication & Authorization
EU -> OP:
OP -> RP: Authentication Response
RP -> OP: UserInfo Request
OP -> RP: UserInfo Response
@enduml
```

<details>
<summary>OpenID Connect Abstract Protocol Flow（PlantUMLソースコード）</summary>
<div>

```
@startuml OpenID Connect Abstract Protocol Flow
autonumber
participant "RP\n(Client)" as RP
actor "End-User" as EU
participant "OP\n(OpenID Provider)" as OP

RP -> OP: Authentication Request
OP -> EU: Authentication & Authorization
EU -> OP:
OP -> RP: Authentication Response
RP -> OP: UserInfo Request
OP -> RP: UserInfo Response
@enduml
```
</div>
</details>

## OpenID Connect Authorization Code Flow

OpenID Connectでも最も利用されるのはAuthorization Code Flowでしょう。
OpenID Connectはユーザーの認証結果をID Tokenの形式でClientへ連携するため、はじめのリクエストもAuthentication Requestとなっていることに注意してください。
加えて、Authorization Serverから返却されたID TokenをClientでは検証してユーザー識別子を取り出すことも忘れないようにしましょう。

※ OpenID ConnectはOAuth 2.0をベースにしており、前述のように[OAuth 2.1](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/)ではImplicit Grantを除外するためこちらでもフローは割愛します。

```plantuml
@startuml OpenID Connect Authorization Code Flow
autonumber
actor "End-User" as EU
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource Server\nUserInfo Endpoint" as RS

EU -> C:
C -> UA: Authentication Request\nState & Nonce
UA -> AS:
AS -> UA: Authenticates End-User
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Obtains End-User Consent/Authorization
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code
AS -> C: ID Token & Access Token
C -> C: Validates ID Token(Nonce)\n& retrieves End-User's\nSubject Identifier
C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response
@enduml
```

<details>
<summary>OpenID Connect Authorization Code Flow（PlantUMLソースコード）</summary>
<div>

```
@startuml OpenID Connect Authorization Code Flow
autonumber
actor "End-User" as EU
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource Server\nUserInfo Endpoint" as RS

EU -> C:
C -> UA: Authentication Request\nState & Nonce
UA -> AS:
AS -> UA: Authenticates End-User
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Obtains End-User Consent/Authorization
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code
AS -> C: ID Token & Access Token
C -> C: Validates ID Token(Nonce)\n& retrieves End-User's\nSubject Identifier
C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response
@enduml
```
</div>
</details>

## OpenID Connect Authorization Code Flow with Refresh Token

Refresh Tokenの発行とAccess Tokenの更新を含むシーケンス図も記載しておきます。

```plantuml
@startuml OpenID Connect Authorization Code Flow with Refresh Token
autonumber
actor "End-User" as EU
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource Server\nUserInfo Endpoint" as RS

EU -> C:
C -> UA: Authentication Request\nState & Nonce
UA -> AS:
AS -> UA: Authenticates End-User
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Obtains End-User Consent/Authorization
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code
AS -> C: ID Token & Access Token & Refresh Token
C -> C: Validates ID Token(Nonce)\n& retrieves End-User's\nSubject Identifier

alt Valid Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response

else Refreshing an Expired Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: Invalid Token Error
C -> AS: New Access Token Request\nRefresh Token
AS -> C: Access Token & Optional Refresh Token & Optional ID Token

alt if an ID Token is returned
C -> C: Validates ID Token
end

C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response
end
@enduml
```

<details>
<summary>OpenID Connect Authorization Code Flow with Refresh Token（PlantUMLソースコード）</summary>
<div>

```
@startuml OpenID Connect Authorization Code Flow with Refresh Token
autonumber
actor "End-User" as EU
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource Server\nUserInfo Endpoint" as RS

EU -> C:
C -> UA: Authentication Request\nState & Nonce
UA -> AS:
AS -> UA: Authenticates End-User
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Obtains End-User Consent/Authorization
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Authorization Code & State
UA -> C:
C -> C: Validates State
C -> AS: Access Token Request\nAuthorization Code
AS -> C: ID Token & Access Token & Refresh Token
C -> C: Validates ID Token(Nonce)\n& retrieves End-User's\nSubject Identifier

alt Valid Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response

else Refreshing an Expired Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: Invalid Token Error
C -> AS: New Access Token Request\nRefresh Token
AS -> C: Access Token & Optional Refresh Token & Optional ID Token

alt if an ID Token is returned
C -> C: Validates ID Token
end

C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response
end
@enduml
```
</div>
</details>

## OpenID Connect Hybrid Flow with Refresh Token

Authorization Code Flowに比べると利用されるケースは少ないですが、ID TokenをDetached SignatureとしてAuthorization CodeやStateの改ざん検知の用途で用いることができるHybrid Flowもまとめておきます。
Refresh Tokenの発行とAccess Tokenの更新も合わせて記載しておきます。

※ 前述のように[OAuth 2.1](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/)ではImplicit Grantを除外するため、`response_type`に`token`を含むフローは割愛します。

```plantuml
@startuml OpenID Connect Hybrid Flow with Refresh Token
autonumber
actor "End-User" as EU
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource Server\nUserInfo Endpoint" as RS

EU -> C:
C -> UA: Authentication Request\nState & Nonce
UA -> AS:
AS -> UA: Authenticates End-User
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Obtains End-User Consent/Authorization
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Authorization Code & State & ID Token
UA -> C:
C -> C: Validates State
C -> C: Validates ID Token(c_hash, Nonce)
C -> AS: Access Token Request\nAuthorization Code
AS -> C: ID Token & Access Token & Refresh Token
C -> C: Validates ID Token &\nretrieves End-User's\nSubject Identifier

alt Valid Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response

else Refreshing an Expired Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: Invalid Token Error
C -> AS: New Access Token Request\nRefresh Token
AS -> C: Access Token & Optional Refresh Token & Optional ID Token

alt if an ID Token is returned
C -> C: Validates ID Token
end

C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response
end
@enduml
```

<details>
<summary>OpenID Connect Hybrid Flow（PlantUMLソースコード）</summary>
<div>

```
@startuml OpenID Connect Hybrid Flow with Refresh Token
autonumber
actor "End-User" as EU
participant Client as C
participant "User-Agent" as UA
participant "Authorization\nServer" as AS
participant "Resource Server\nUserInfo Endpoint" as RS

EU -> C:
C -> UA: Authentication Request\nState & Nonce
UA -> AS:
AS -> UA: Authenticates End-User
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Obtains End-User Consent/Authorization
UA -> EU:
EU -> UA:
UA -> AS:
AS -> UA: Authorization Code & State & ID Token
UA -> C:
C -> C: Validates State
C -> C: Validates ID Token(c_hash, Nonce)
C -> AS: Access Token Request\nAuthorization Code
AS -> C: ID Token & Access Token & Refresh Token
C -> C: Validates ID Token &\nretrieves End-User's\nSubject Identifier

alt Valid Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response

else Refreshing an Expired Access Token
C -> RS: UserInfo Request\nAccess Token
RS -> C: Invalid Token Error
C -> AS: New Access Token Request\nRefresh Token
AS -> C: Access Token & Optional Refresh Token & Optional ID Token

alt if an ID Token is returned
C -> C: Validates ID Token
end

C -> RS: UserInfo Request\nAccess Token
RS -> C: UserInfo Response
end
@enduml
```
</div>
</details>

# 最後に
今回はOAuth 2.0やOpenID Connectのシーケンス図をまとめました。
各社IdPと連携する、（あまりないかもしれませんが）自社で認証・認可サーバーを実装するなどの際に役立ててもらえたら幸いです。

記載ミスなどみつけたら記事にコメントいただくか、以下のGithubにもPlantUMLのソースコードをあげたのでプルリクを投げてもらえたらと思います。

https://github.com/kura-lab/oauth-oidc-sequences

18日目も担当する予定なので楽しみにしてもらえたらと思います。