Created
April 4, 2025 23:55
-
-
Save bills-appworks/0a8d359f9d3dc9c66d3453c1361d0259 to your computer and use it in GitHub Desktop.
OAuth概要フロー(クライアント:シングルページアプリケーション版)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@startuml | |
title | |
OAuthフロー(PKCE/PAR/DPoP含む) | |
フロー:認可コードグラント(+リフレッシュトークン) | |
クライアントタイプ:シングルページアプリケーション(OAuth:Public) | |
end title | |
actor "リソースオーナー\n(ユーザー)" as user | |
participant ua [ | |
ユーザーエージェント | |
(Webブラウザ等) | |
] | |
participant spa [ | |
シングルページ | |
アプリケーション | |
(JavaScript等 | |
クライアントサイド) | |
] | |
box "OAuthサーバー\n(認可サーバー)" | |
participant par_endpoint [ | |
プッシュ認可 | |
エンドポイント | |
] | |
participant auth_endpoint [ | |
認可 | |
エンドポイント | |
] | |
participant token_endpoint [ | |
アクセストークン | |
エンドポイント | |
] | |
end box | |
participant resource [ | |
リソースサーバー | |
(API・データリポジトリ等 | |
認可ターゲット) | |
] | |
autonumber | |
note over spa | |
[SPAでのトークン保護] | |
認可サーバーから受け取ったトークンの格納先候補 | |
a. LocalStorage | |
b. SessionStorage | |
c. cookie | |
d. メモリ | |
e. ServiceWorker | |
f. WebCrypto API | |
a-cについてはクロスサイトスクリプティングの | |
リスクが比較的高い | |
end note | |
== 認可コードリクエスト == | |
user -> ua : アクセスリクエスト(操作) | |
ua -> spa : アクセスリクエスト(操作) | |
note over spa | |
1. PKCEシークレット(ランダム文字列)生成 | |
2. PKCEハッシュ作成(シークレット→SHA256) | |
3. PKCEハッシュbase64urlエンコード(SHA256→base64url) | |
end note | |
note over spa | |
PKCEシークレットをLocalStorage/SessionStorage格納 | |
(アクセストークンリクエスト時に参照) | |
end note | |
note over spa | |
アプリ固有状態生成 | |
end note | |
spa -> par_endpoint : プッシュ認可リクエスト\n(PAR) | |
note left | |
Host: <プッシュ認可エンドポイントサーバー> | |
Content-type: application/x-www-form-urlencoded | |
cliend_id=<クライアントID> | |
redirect_uri=<リダイレクトURI> | |
scope=<スコープ> OIDCであれば+openid | |
state=<アプリ固有状態> | |
code_challenge=<PKCEハッシュbase64urlエンコード> | |
code_challenge_metohd=S256 (ハッシュがSHA256の場合) | |
end note | |
spa <-- par_endpoint : リクエストURI応答 | |
note right | |
{ | |
request_uri: urn:ietf:params:oatuth:request_uri:<リクエストに紐づく識別子> | |
expires_in: <リクエストURI有効期限> | |
} | |
end note | |
ua <-- spa : 認可エンドポイントへのリダイレクト応答 | |
note over ua, auth_endpoint | |
client_id=<クライアントID> | |
request_uri=urn:ietf:params:oatuth:request_uri:<リクエストに紐づく識別子> | |
end note | |
ua -> auth_endpoint : リダイレクトリクエスト | |
note over user, auth_endpoint | |
ユーザー認証(IDパスワード、MFA等) | |
→ユーザーエージェントセッションキャッシュ済でユーザー操作無い場合あり | |
end note | |
ua <-- auth_endpoint : 認可意思確認画面応答 | |
user <-- ua : 認可意思確認画面レンダリング | |
user -> ua : 認可許諾操作 | |
ua -> auth_endpoint :リソースオーナーの認可許諾確認 | |
note over par_endpoint, token_endpoint | |
リクエスト内容に応じた認可コード生成 | |
end note | |
ua <-- auth_endpoint : リダイレクトURIへのリダイレクト応答 | |
note over ua, auth_endpoint | |
code=<認可コード> | |
state=<アプリ固有状態> | |
end note | |
ua -> spa : リダイレクトリクエスト | |
note over spa | |
リクエスト時と応答のアプリ固有状態を | |
一致チェック(CSRF防止) | |
end note | |
== アクセストークンリクエスト == | |
note over spa | |
1. DPoP証明生成(ヘッダ・ペイロード) | |
2. DPoP証明ヘッダ・ペイロードをそれぞれbase64エンコード | |
3. 署名無しトークン生成 <base64 DPoPヘッダ>.<base64 DPoPペイロード> | |
4. 署名無しトークンを電子署名し署名生成 | |
5. 署名をbase64エンコード | |
end note | |
spa -> token_endpoint : アクセストークンリクエスト | |
note left | |
Host: <アクセストークンエンドポイントサーバー> | |
DPoP: <base64 DPoPヘッダ>.<base64 DPoPペイロード>.<base64署名> | |
grant_type=authorization_code | |
code=<認可コード> | |
redirect_uri=<リダイレクトURI> | |
code_verifier=<PKCEシークレット> | |
client_id=<クライアントID> | |
client_secret=<クライアントシークレット> | |
end note | |
note over par_endpoint, token_endpoint | |
1. DPoP署名検証 | |
2. DPoPクレーム(ヘッダ・ペイロード内容)検証 | |
end note | |
note over par_endpoint, token_endpoint | |
1.PKCEシークレットからハッシュ計算 | |
2.最初のリクエストのPKCEハッシュと比較検証 | |
end note | |
note over par_endpoint, token_endpoint | |
アクセストークン関連生成 | |
{ | |
token_type: Bearer | |
access_token: <アクセストークン> | |
refresh_token: <リフレッシュトークン> | |
expires_in: <トークン有効期限> | |
id_token: <(OIDCの場合)IDトークン> | |
} | |
end note | |
spa <-- token_endpoint : アクセストークン応答\n(リフレッシュトークン内包) | |
note over spa | |
1. DPoP証明生成(ヘッダ・ペイロード) | |
2. DPoP証明ヘッダ・ペイロードをそれぞれbase64エンコード | |
3. 署名無しトークン生成 <base64 DPoPヘッダ>.<base64 DPoPペイロード> | |
4. 署名無しトークンを電子署名し署名生成 | |
5. 署名をbase64エンコード | |
end note | |
spa -> resource | |
note left | |
Authorization: <アクセストークン> | |
DPoP: <base64 DPoPヘッダ>.<base64 DPoPペイロード>.<base64署名> | |
end note | |
note over resource | |
1. DPoP署名検証 | |
2. DPoPクレーム(ヘッダ・ペイロード内容)検証 | |
end note | |
note over resource | |
アクセストークン検証 | |
(イントロスペクション:ローカル/リモート) | |
end note | |
spa <-- resource : 対象リソースレスポンス | |
ua <-- spa : アクセスリクエスト(操作)に沿った画面レンダリング | |
user <-- ua : アクセスリクエスト(操作)結果表示 | |
== アクセストークン有効期間中のリクエスト == | |
user -> ua : アクセストークン対象リソースを含む\nアプリ利用操作 | |
ua -> spa : アクセストークン対象リソースを含む\nアプリ操作リクエスト | |
note over spa | |
1. DPoP証明生成(ヘッダ・ペイロード) | |
2. DPoP証明ヘッダ・ペイロードをそれぞれbase64エンコード | |
3. 署名無しトークン生成 <base64 DPoPヘッダ>.<base64 DPoPペイロード> | |
4. 署名無しトークンを電子署名し署名生成 | |
5. 署名をbase64エンコード | |
end note | |
spa -> resource | |
note left | |
Authorization: <アクセストークン> | |
DPoP: <base64 DPoPヘッダ>.<base64 DPoPペイロード>.<base64署名> | |
end note | |
note over resource | |
1. DPoP署名検証 | |
2. DPoPクレーム(ヘッダ・ペイロード内容)検証 | |
end note | |
note over resource | |
アクセストークン検証 | |
(イントロスペクション:ローカル/リモート) | |
end note | |
spa <-- resource : 対象リソースレスポンス | |
ua <-- spa : アプリ利用操作リクエストに沿った応答 | |
user <-- ua : アプリ利用操作結果表示 | |
... トークン有効期間 ... | |
== リフレッシュトークン == | |
note over spa | |
1. DPoP証明生成(ヘッダ・ペイロード) | |
2. DPoP証明ヘッダ・ペイロードをそれぞれbase64エンコード | |
3. 署名無しトークン生成 <base64 DPoPヘッダ>.<base64 DPoPペイロード> | |
4. 署名無しトークンを電子署名し署名生成 | |
5. 署名をbase64エンコード | |
end note | |
spa -> token_endpoint : アクセストークン更新リクエスト | |
note left | |
Host: <アクセストークンエンドポイントサーバー> | |
DPoP: <base64 DPoPヘッダ>.<base64 DPoPペイロード>.<base64署名> | |
grant_type=refresh_token | |
refresh_token=<リフレッシュトークン> | |
client_id=<クライアントID> | |
client_secret=<クライアントシークレット> | |
end note | |
note over par_endpoint, token_endpoint | |
1. DPoP署名検証 | |
2. DPoPクレーム(ヘッダ・ペイロード内容)検証 | |
end note | |
note over par_endpoint, token_endpoint | |
リフレッシュトークン検証 | |
end note | |
note over par_endpoint, token_endpoint | |
新アクセストークン関連生成 | |
end note | |
spa <-- token_endpoint : 新アクセストークン応答\n(新リフレッシュトークン内包) | |
@enduml |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment