認可コードフローを図解|OAuth2.0(OIDC)の仕組みをSPAのSSO機能を例に解説

はじめに

OAuth2.0やOIDCといったプロトコルの仕組みのベースになっている

認可コードフローについてSPA(Single Page Application)にSSO機能を

keycloak(認証認可サーバ)で付与する例を使って図解しました。

 

僕が開発リーダーをやっている開発チームのメンバーには認証認可周り詳しい人がおらず、

SPAとAPIとリリース間際の脆弱性診断で認証認可周りの突っ込みを受けて

リリース間際に自分で一から調べて自分で対応するという悲惨な目にあいました、、、、

 

そんな悲惨な経験から最低限理解しておくと役に立ちそうなポイントに絞って、

認可コードフローの全体概要をまとめました。

 

 

SPAにSSO認証機能を付与したシステムの構成概要

今回は実際に認証認可サーバの設定、フロントエンド、

リソースサーバの細かい設定や開発周りは省略しますが、

 

アプリケーションのシステム構成はこんな感じで、

ローカル環境で動作確認した際の

具体的なリクエストやレスポンスを例に交えながら認可コードフローについて説明します。

 

 

 

SPAでSSOしてリソースサーバ(Rest API)連携するまでの認可コードフロー

認可コードフローを絵にするとこんな感じです。

 

 

上のフローで重要なポイントに絞って説明していきます。

 

認可リクエスト|SPA→認可サーバ

未ログイン状態でユーザがSPAにアクセスしたら、

SPAはkeycloak-js(認可サーバのアダプタ)を利用して

認可リクエストパラメータを作成して認可エンドポイントにアクセスします。

 

認可エンドポイントリクエスト例
GET http://localhost:8180/auth/realms/レルム名/protocol/openid-connect/auth
 ?client_id=frontend
 &redirect_uri=http%3A%2F%2Flocalhost%3A3000%2F
 &state=1cda14d9-cd93-4744-89b6-808b799c8013
 &response_mode=fragment
 &response_type=code
 &scope=openid
 &nonce=62e3d51f-5f96-40a8-8e33-34fed33dc08a
 &code_challenge=x7dfF7VqbW1oA0HvuLgZATVwkgfoo_3zeGukAPXKsgo
 &code_challenge_method=S256

 

ここではパラメータについての詳細な説明は省略しますが、

興味がある方はAuthlete川崎さんの以下の記事がわかりやすいのでオススメです。

>>OAuth 2.0 全フローの図解と動画

 

認可コード取得|認可サーバ→SPA

ログイン画面でIDとパスワードを入力してログインすると

認可決定エンドポイントにアクセスして、リダイレクトで認可コードが返却されます。

 

認可決定エンドポイントレスポンス例
HTTP/1.1 302 Found
Location:http://localhost:3000/
 #state=1cda14d9-cd93-4744-89b6-808b799c8013
 &session_state=718f7bc5-da43-4fa7-b86f-6a936475203e
 &code=1e5712f4-8d9d-4009-9089-32639892d871.718f7bc5-da43-4fa7-b86f-6a936475203e.a58f25ac-2660-414d-ae3f-725ec78465b1

 

アクセストークン取得|SPA→認可サーバ

keycloak-jsでアクセストークンを取得してリソースサーバ呼び出しのために、

例えばaxiosの共通ヘッダのAuthorizationに設定しておきます。

 

アクセストークンエンドポイントリクエスト例
POST http://localhost:8180/auth/realms/resona/protocol/openid-connect/token
 code: 1e5712f4-8d9d-4009-9089-32639892d871.718f7bc5-da43-4fa7-b86f-6a936475203e.a58f25ac-2660-414d-ae3f-725ec78465b1
 grant_type: authorization_code
 client_id: frontend
 redirect_uri: http://localhost:3000/
 code_verifier: E1c0gRF13FrdGf06WxhpB4qlzftePoTAHhf2ZJ7GxygcEKvu81FUAnhFqvSJTa6G3zBq2caFfX1XFWQnaOevdxAEaw6hL2t7

 

アクセストークンレスポンス例
{"access_token":"eyJhbGciOiJSUzIH・・・"
 ,"expires_in":60
 ,"refresh_expires_in":140
 ,"refresh_token":"eyJhbGciOiJIUzI1・・・"
 ,"token_type":"Bearer"
 ,"id_token":"eyJhbGciOiJSUzI1・・・"
 ,"not-before-policy":0
 ,"session_state":"718f7bc5-da43-4fa7-b86f-6a936475203e"
 ,"scope":"openid profile"}

 

今回はアクセストークンをkeycloak-jsライブラリの変数で保持させていますが、

localStorageや変数で保持させているとXSS攻撃を受けると

アクセストークンにアクセス(抜き取られる)できてしまいます。

 

その対策としては、

そもそもXSSに対する根本対応を取るべきだとは思いますが、

 

ただ、、、

アクセストークンを盗まれても

それだけでは不正にリソースサーバにアクセスできないようにDPoPを導入するか、、

フロントエンドにアクセストークンを晒さないようにBFFを用意して

そこで認可サーバとやり取りをさせる仕組みにした方がよりセキュアです。

 

(が、、、対応工数と効果と求められるセキュリティ要件とを

天秤にかけて僕が携わっているプロダクトでは現状そこまでやっていないです)

 

リソースアクセス〜トークン検証|SPA→リソースサーバ→認証認可サーバ

SPAはAuthorization ヘッダ付きでリソースサーバのエンドポイントをコールし、

リソースサーバはspring-boot-starter-oauth2-resource-serverを利用して

認可サーバのトークンイントロスペクションエンドポイントを利用して

アクセストークンを検証します。

 

先ほどの図の②~⑦までの

アクセストークン発行までの仕様を定めているものが

OAuth2.0と呼ばれるものであり、

それを発展させてIDトークン発行の仕様を定めているものがOIDC(OpenID Connect)です。

 

まとめ

OAuth2.0でアクセストークンが発行されるまでの、

認可コードフローの流れや、

発行されたアクセストークンをリソースサーバで

トークンイントロスペクションで検証してリソースを返却する流れを見てきました。

 

SPAの開発に携わるエンジニアの方

(バックエンド、フロントエンド、インフラに関わらず)は

最低限この辺りはざっくり理解しておくことで、

 

認証認可周りのどこかでセキュリティ的に問題があった際、

原因調査のあたりがつけやすくなります。

 

さらに、

今回説明した認可コードフローの概要がつかめたら、

Financial-grade API(FAPI)といったさらに高セキュアな仕様も

ある程度すんなり理解できるはずです。

 

(ちなみにkeycloakはFAPIや他にもCIBA等にも対応しており、

まだまだ使い倒したいと思っています。)

 

おまけ

Spring Bootで作成したRestAPIを認証認可サーバで保護したり、

OIDCやOAuth2.0の違いを図解したり、

認証認可周りの諸々をまとめた記事を作りました。

是非ご覧ください。

keycloakでAPI保護・SPAログイン機能設定例、OIDC・OAuth・PKCE・認可コードフロー図解などまとめ

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください