Closed9

OAuth 2.0 と OpenID Connect を実装しながら学ぶ

nissy-devnissy-dev

OAuth 2.0 の認可フローは、RFC には 4つ定義してある。OAuth は認可のためのプロトコルなので、この5つでアクセストークンの取得の仕方が変わる。

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

そして、どれが一番良い方法なの?という話だが、最近は状況に応じて次の2つが使われるらしい。

  • ブラウザやモバイルなどの自身の認証情報を安全に保持できない公開クライアントの場合
    • Authorization Code Flow (with PKCE)
  • サーバー間通信などの自身の認証情報を安全に保持できるクライアントの場合
    • Client Credentials Flow

https://www.authlete.com/ja/kb/oauth-and-openid-connect/grant-type/how-to-choose-the-appropriate-oauth-2-flow/

https://auth0.com/docs/ja-jp/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use

今回は Authorization Code Flow (with PKCE) を簡略化して作っていくことにしたい。

ちなみに PKCE (ピクシーと読む) とは、悪意のあるクライアントに redirect_url を利用してトークンを横取りされないための拡張仕様である。

https://zenn.dev/tell1124/articles/f6a4a12b3172ad

nissy-devnissy-dev

今回は Authorization Code Flow (with PKCE) を簡略化して作っていくことにしたい。
クライアントはブラウザ上のアプリケーションを想定していて、リソースオーナー (自分) がクライアントから認可を要求されて、許可を出した後の流れ (Github とかの OAuth の画面で OK を出した後の流れ) の sequence 図は次のようになる。

nissy-devnissy-dev

JWT の話は、次の2つの記事がとてもわかりやすかった。

https://developer.mamezou-tech.com/blogs/2022/12/08/jwt-auth/

https://qiita.com/TakahikoKawasaki/items/970548727761f9e02bcd

JWT の仕様としては JSON データを URL セーフにどう token 化するかしか書いてない。OAuth のアクセストークンを JWT で扱うときの仕様として、RFC 9068: JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens が重要になる。

アクセストークに紐づく情報をどう管理するかの方法としては、auth server の DB に保存して resource server が auth server へ API 経由で問い合わせる識別子型と、アクセストークンの中に情報を埋め込んでしまう (要は JSON を JWT で token 化するということ) 内包型の2つのパターンがある。

内包型の方が resource server から auth server へのリクエストがなくなって嬉しいが、もちろん暗号化や署名をしないと簡単に偽造されてしまうという問題がある。そこで 上記の RFC 9068 が重要になる。

RFC 9068 では、データの署名には JWS をデータの暗号化には JWE を使うことを規定している。どちらも IETF で策定されている仕様である。なお JWS は事実上必須になっている感じがある。

JWE の詳細はこちらも参考になる
https://auth0.com/docs/ja-jp/secure/tokens/access-tokens/json-web-encryption

JWS と JWE は、どちらも JSON 形式と Compat 形式があり、JWT では compat 形式を利用することが仕様で決まっている。JWT が ピリオドで連結されている形式をよく見るが、これは compat 形式由来である。

https://qiita.com/TakahikoKawasaki/items/1c1bcf24b46ebd2030f5

また署名や暗号化のアルゴリズムには、非対称鍵認証方式が推奨されている。この場合、auth server はリソースサーバーに公開鍵を配る必要があるが、これは JWKS と呼ばれる仕様を満たすエンドポイントを auth server が公開することで実現されることがある。

nissy-devnissy-dev

次はとうとう OpenID Connect の実装かな〜と思ったけど、Token Introspection エンドポイントも実装した方が良さそうだよと chatgpt に教えてもらったのでみている。

要は token の発行と token の利用のタイミングが違うので、発行から利用までの間に token が失効したり、scope などが変化してないかを auth server に問い合わせることを可能にするエンドポイントのことみたい。

nissy-devnissy-dev

ID Token を返す実装までやった。 User Info エンドポイントとか /.well-known/openid-configuration とかの実装はしてない。

今気づいたけど、エラーが起きた時にどういうエラーを返すべきなのかもちゃんと仕様で定義されているのでそれに従うべきみたいだ
https://openid.net/specs/openid-connect-core-1_0.html#AuthError

このスクラップは6ヶ月前にクローズされました