概要
OAuthをベースとしたHTTPベースの認証・認可1を提供するプロトコル
OAuth2.0
2012年から公開されたプロトコル
MCP2でも使われている。
ユーザではなくアプリに対して認可を行う
ID・パスワードで認可を行い、アクセストークを用いてアクセスする
★ユーザ情報を取得する使用が定まっておらず、独自に実装しなくてはいけない
OAuthに対し、OIDCでは、
認証時のユーザ情報を記載したIDトークンの追加し、
ユーザ情報を取得するためのエンドポイントを定めた
アクセストークンとIDトークンを使う
IDトークンはクライアント側のみで使う|ユーザ情報が含まれる
アクセストークンでもユーザ情報を取得できるが、IDトークンに含まれるため使わないケースがある
OIDC上の主な登場人物
ユーザ:利用者自身
IdP:アクセス、IDトークンを発行するサーバ
Client:認証、認可を利用するアプリ
ResourceServer:アクセストークンを使ってアクセスされるサーバ
SPA(Single Page Application):JavaScriptでブラウザでページ切り替え
MPA(Multi Page Applicatioin):サーバからページ送信
BFF(Backend For Frontend):SPAでページ切り替え apiでデータ送信
ClientID:ClientのID
ClientSecret:Clientのパスワード
OIDCではClientは主に2種類に分けられる
コンフィデンシャル:MPA、BFFなどサーバ側でClientが動作する
ClientIDとClientSecretが発行され、ClientSecretを使って認証する
パブリック:SPAやネイティブアプリなどユーザ端末でClientが動作する
ClientIDのみでClientSecretは発行されない。
エンドポイント
ClientやIdPがアクセスを受ける場所|IdPのエンドポイントは仕様でルール化されてる
認可エンドポイント
ユーザの認証を開始するエンドポイント
例.メルカリでGoogleでログインで認可ポイントにリクエストが送信されGoogleの認証画面を表示
リダイレクションエンドポイント
IdPの画面でログインした時にClientにリダイレクト3される時のエンドポイント
このリクエストでトークン取得のための情報、もしくはトークンを得る
認可レスポンスと呼ぶ
トークンエンドポイント
ClientがIdPからトークンを取得するためのエンドポイント
ClientからIdPへのアクセスをトークンリクエスト、逆の応答をトークンレスポンスと呼ぶ
フロー
エンドポイントを使うデータのやり取り
認可コードフロー
トークン取得前に認可コード(ランダムな値)をClientに送信
Clientは認可コードでトークンを取得する
①ブラウザからIdPの認可エンドポイントへアクセスしてスタート
②ログイン画面で認証すると、IdPから認可コードをブラウザに送信
③ブラウザはClientのリダイレクションエンドポイントへ認可コードを送信
④ClientはIdPのトークンエンドポイントに認可コードを送信
⑤IdPはトークン発行送信、Clientが取得

インプリシットフロー
SPAのClientで使用することを想定し
JSが他ドメインURLにアクセスできなかったため作られたがCORS4が出てきておkになった
認可レスポンスにトークンを含めるためClientからIdPへのアクセスがなくなり、
トークンエンドポイントを使わないようにできるが、セキュアでないためRFC9700より推奨されていない
OAuth2.1では仕様から外されている
ハイブリッドフロー
認可コードとフローは同じ
リダイレクションエンドポイントにトークンを含めることができる点が異なる
RFC9700よりトークン漏れの可能性があるあるため推奨されていない
ただ、Max-Up攻撃対策で使われる
クライアントクレデンシャルフロー
ユーザは登場せず、Client自身をIdPに認証してもらう
ClientIDとSecを渡してアクセストークンを取得する(IDトークンはなし)
リソースオーナークレデンシャルパスワードフロー
Clientにユーザクレデンシャルを渡して、そこからトークンリクエストを行う方法
Clientに高セキュリティが求められる
IdPのログイン画面でなく、Clientの画面になるためユーザビリティは高い
インプリシット、ハイブリッドと同様推奨されていない
トークンの種類
アクセストークン
ClientがRSサーバにアクセスするために必要なクレデンシャル
ハンドル型
IdPの内部データと紐づけるトークン
RSサーバはちんぷんかんぷんなランダム文字列
オパークトークンとも呼ばれる
アサーション型
Clientを特定するIDや有効期限の情報が含まれ、RSサーバでも理解可能
電子署名されてるのでIdPにアクセスせずに正当性を証明できる
主にJWT形式が使われる
オパークトークン
RSサーバはClientから送信されたアクセストークンをIdPに送信して検証する
IdPで検証するのでその時の有効性がわかる
ネットワーク負荷が高まる|IdP停止時に検証できない
JWT
RFC7519で標準化されているデータ形式
Claimと呼ばれるキーと値をJSON形式で記載
base64URL5で電子署名される
Claimは標準化されてるが独自で決めることもできる
ヘッダにメタデータ|ペイロードに実データ|.で区切って上二つを電子署名したデータを繋いで作られる
RSサーバは起動時にIdPの公開鍵をダウンロードしておいてそれで電子署名を検証する
IdPにアクセスせず検証できるため、ネットワーク負荷やIdP停止時も大丈夫
リアルタイムでアクセストークンの有効性がわからない
IDトークン
オパークは使われない
ユーザの認証時の情報を含んだJWT形式のデータ
Clientが知るためのものでRSサーバに送られない
アクセストークンとしても使用できるが、セキュリティに関するプラクティス6も変わるため特別な理由がない限りはそんな使い方しない
ユーザの権限
ID、アクセストークンに含めれるが、IdPの独自画面やAPIでの制御が必要、ロックイン7になる
RSサーバやClient、もしくは第三のシステムで集中管理する手もあるが、実装に負担
リフレッシュトークン
IdPにアクセストークンを再発行してもらうトークン
オパーク、JWT両方使われる
アクセストークンの有効期限が切れた時に使われる
アクセストークンより長めに有効期限がある
認可コードフローの詳細
認可リクエスト
まずこれから始まる
IdPに対してフローを始めるための情報、何のフローかアクセスしたい範囲などを含める
一般的にはGETが使われ、URLエンコーディング8されている
パラメータ
scope:ユーザのどの情報へのアクセスを許可してほしいかを指定
IdPの認可画面に表示される
ユーザの認可にてScopeの情報がアクセストークンを介してRSサーバに渡される
RSサーバによってアクセス制御する
response_type:認可レスポンスで欲しいデータ、フローがここで指定される
client_id:IdPがClientを登録する時に一意に定めるID
IdPによっては開発者によって決められることもある
Client開発者によって認可リクエストに含める
redirect_uri:Clientリダイレクションエンドポイントを指定
認可レスポンス(リダイレクトレスポンス)で指定してもらう
IdPに事前に登録しておく
stateパラメータ:Clientでランダム生成
リダイレクトレスポンスに含めてもらうことで正当性を確認
nonceパラメータ:Clientでランダム生成
IDトークンにnonce Claimとして含めてもらう
code_challenge,
code_challenge_method:PKCEで使われる
認可レスポンス
ユーザがIdPにログインし認可された後返されるリダイレクトレスポンス
code(認可コード)とstateが含まれる
リダイレクションエンドポイントへのリクエスト
ブラウザからClientのリダイレクションエンドポイントへアクセスされる
ClientがBFFの場合、リクエスト時のstateとURLのstateを検証する
トークンリクエスト
Clientが認可コードを取得した後はトークンリクエストを行う
HTTPではPOSTが使われる
ClientがBFFの場合、コンフィデンシャルなClientとしてIdPで認証される
Basic認証でClientIDとSec(b64エンコード)が使われる
トークンレスポンス
トークンのデータはIdPからのトークンレスポンスにJSON形式で返される
ClientはIDトークンの正当性を確認する
チェックはライブラリがある
PKCE(Proof Key Code Exchange)
認可コードが漏洩した場合の対策
OAuth2.1から必須
トークンリクエストにClientしか知らないcode_veriferを含め、IdPがそれをチェック
アクセストークン取得後RSサーバへのアクセス
アクセストークンを渡す必要がある
Bearer9トークンで渡す
RSサーバ側の処理
アクセストークンの検証
JWTの場合電子署名をIdPからの公開鍵を使って検証
オパークトークンの場合IdPのイントロスペクションエンドポイントへ都度検証
イントロスペクションリクエスト
HTTPのPOSTメソッドを使う
Keycloakでは不正アクセス対策でRSサーバをbasic認証する
イントロスペクションレスポンス
アクセストークンが有効か否かの結果と有効期限(UNIX時間10)などが返される
アクセストークンのリフレッシュ
アクセストークンの再発行にはリフレッシュトークンを利用する
トークンレスポンスにアクセストークンと一緒に送られる
リフレッシュリクエスト
トークンエンドポイントにリフレッシュトークンを送信
コンフィデンシャルなClientの場合は認証がいる(Basic認証など)
リフレッシュレスポンス
リフレッシュトークンがJSON形式で返される
リフレッシュローテーション
リフレッシュトークンを発行した時に前のリフレッシュトークンを無効にする
リフレッシュトークン漏洩対策
ユーザ情報の取得
アクセストークンに合わせて取得するIDトークンに含まれる
IdP側でユーザ情報の更新があった場合まずい、情報も限られてる
RSサーバはIDトークンを受け取らないためユーザ情報を取得するには仕組みが必要
ユーザ情報リクエスト
IdPへBearerトークンでアクセストークンを指定してリクエスト
ユーザ情報レスポンス
JSON形式でユーザ情報が返される
ログアウト
ClientかIdPからログアウトする
ClientでログアウトしてIdPでログインしている場合、Clientがログインできなかったりする
Clientがログアウトする時にIdPに通知する必要がある
OpenID Connect RP Initiated Logout
ログアウトイベント時にClientからIdPへログアウトリクエストを送信する
Clientのログアウトはリクエスト前後どちらでも良い
IdPはブラウザへレスポンスし、ブラウザはポストログアウトリダイレクトURIへリダイレクトし、Clientをログアウトする
シングルログアウト
一つのアプリでログアウトすると他のアプリもログアウトする
OpenID Connect Front-Channel Logout
SPAやネイティブアプリのようにClientがユーザ端末で動作する場合に使用
IdPからのレスポンスに他のClientにアクセスする
OpenID Connect Buck-Channel Logout
MPAやBFFみたいにClientがサーバで動く場合に使用
IdPから他ClientのログアウトURIへアクセスする
Keycloak
オープンソースで開発されているIdP
OIDCやSAMLに対応してる
LDAPやADとの外部連携、シングルログアウト機能あり
ユーザやClientをRealmという単位でグルーピング
検証
KeycloakとClientをローカルマシンで起動し、
SPA,MPA,ネイティブ,Batchアプリでシングルサインオン、シングルログアウトを確認した。
所感
認可コードフローについて詳しく学べたのが良い知見となった。
Kecloakの操作もできたので今後に活かせると考える。
- 認証と認可の違い:認証とはその人が本人か確認すること、認可は権限付与、アクセス制御のこと ↩︎
- MCP(Model Context Protocol):AIアプリが外部ツールやデータを呼び出す仕組み ↩︎
- 特定のURLにアクセスした時に、別のURLへ転送する技術 ↩︎
- CORS(Cross-Origin Resource Sharing):JSによる他ドメインへのリクエストを許可する仕組み ↩︎
- Base64でエンコードしたものをURLに変換 ↩︎
- 手法、慣行 ↩︎
- 特定の対象に頼りきりになるみたいな ↩︎
- URLに使えない日本語などの文字を使える文字に置き換えること ↩︎
- Web APIやアプリケーションで認証・認可に使用される、一時的でランダムな文字列(トークン) ↩︎
- 1970/1/1からの経過秒数 ↩︎

コメント