🍵

OAuth2.0はなぜ複雑に見えるのか

2024/03/16に公開

はじめに

OAuth2.0で、認可コードによる付与ってこんな仕組みだそうです。難しくないですか?
すごい画像
https://datatracker.ietf.org/doc/html/rfc6749#section-4.1
OAuth2.0を生み出した人々への敬意を込めて、この図がどれだけの問題を解決してそうか、を想像していきます

だれに向けたか

だれに向けてないか

  • OAuth2.0についてわかりやすく説明された記事を全く読んだことがない人
  • OAuth2.0が肌に馴染んでいる人

なぜ書いたか

OAuth2.0がどういう仕組みか、どんな用語があってどうやって使われているか、は非常にわかりやすい書籍や記事がたくさんあります。
一方で、「なんでリダイレクトさせるの?」「認可コードほんとにいるの?ないと困るの?」といったなぜ?に答えてくれる書籍や記事はぱっと探した限り見当たりませんでした。
そこで、「この仕組みがあるのは多分こういう背景だろう」と想像して、帳尻が合うような資料を作成しました。

注意

歴史的経緯や正確なことはわからないので、何か知ってる方や修正点に気づいた方は、優しくコメントください。検知したら記事を修正します。

この記事で扱うもの

  • OAuth2.0の複雑さの背景にある気持ち(の想像)
  • なるべく丸暗記を避けて、OAuth2.0の仕組みを説明できるようになるための具体的な方法
  • 認可/認証を発展させて来た人たちがいかにすごいかがちょっとわかる例

この記事で扱わないもの

  • 以下は他の書籍や記事が十分わかりやすいので、そちらを参照してください
  • OAuth2.0の仕組みそのもの
  • OAuth2.0に出てくるいくつかの重要概念
    • リフレッシュトークン
    • state
    • 認可コードによる付与以外の方式
    • PKCE
  • OpenID Connectなど

この記事のゴール

OAuth2.0における認可コードによる付与のシーケンス図を、ある意味必然かのような気持ちで導出することを目指します。
複数書籍を参考に書くとおおよそこんな感じです。

これを暗記ではなく、なるべくストーリー的に導出します。

シーケンス図の導出

ケース設定

  • 登場人物
    • Aさん(UserAgent、browser)
    • サードパーティアプリT(Client)
    • サービスX(Resource Server)
  • シーン(Usecase)
    • Aさんが、サードパーティアプリで「最新の起床記録を取得する」ボタンを押すと、サービスXから最新の「今起きた」という投稿を取得するようにしたい

スタート: Basic Authを使ってID/パスワードをそのまま渡す

何が問題?

  • サードパーティアプリが脆弱だったら、サービスXのID/パスワードが漏れ、過去の全「今起きた」投稿が盗まれてしまう恐れがある

ID/パスワードとは別に設定する許可トークン的なものを渡すことにする

何が問題?

  • Aさんは、サードパーティアプリとサービスXに対して、新たに許可トークンを管理しないといけなくなる
    • サービスが増えていくと、管理しないといけないトークンが山積みになり、管理が無理に
    • 「投稿を取得する」以外のアクションを許可しようと思ったら、また別のトークンを発行したり、、

許可トークン的なもの(以下アクセストークンと呼ぶ)の発行や管理を他の人に任せる

何が問題?

  • 他の人Yは「サービスXの権限をサードパーティアプリTに移譲する」許可を与えてもいい立場じゃないと、なりすまされる危険がある
  • Aさんがいちいち他の人Yに登録を依頼するのが面倒。YからAに依頼してほしい
  • サードパーティアプリTが他の人Yから「Aさんのアクセストークンをもらっていい」という許可をもらってるかどうかを確認しないと、なりすまされる危険がある

他の人Yを指名しつつ、Aさんが何も考えなくていいようにして、なりすましを防ぐ

  • 他の人Yは、サービスXの公式サーバー(以下、認可サーバー)とする
  • Aさんが能動的に登録依頼を出さなくてもいいようにする
  • サードパーティアプリTが「Aさんのアクセストークンをもらっていい」という許可をもらってるかを確認する

何が問題?

  • 認可サーバーYが、Aさん(固定の公開IPアドレスを持ってない)を特定できないので、Y → A方向のリクエストが送れない

Aさんから認可サーバーYにリクエストできるように、サードパーティアプリTが認可サーバーに最初に問い合わせるときのURL(以下、認可エンドポイント)をAさんに渡してリダイレクトさせる

何が問題?

  • 認可サーバーYからすると、Aさんが本人かわからないので、なりすましの危険がある

Aさんが本人であることを認証させる

何が問題?

  • 投稿取得のトリガーが認可サーバーからのアクセストークンになってしまっている(クライアント/サーバー関係が逆転している)
    • 例えば、認可サーバーYからサードパーティアプリTにアクセストークンをPOST的に発行したとき、サードパーティアプリTがもし受け取り失敗しても、再発行できない

サードパーティアプリTから認可サーバーYにアクセスできるようにする

何が問題?

  • 認可サーバーYは、サードパーティアプリTが本物であるかがわからないので、なりすましの危険がある

サードパーティアプリTが本人であることを証明(クライアント認証)する

何が問題?

  • サードパーティアプリTからアクセストークンのリクエストを受け取ったとき、それがAさんの指示によるものなのか、また何をできるようにするリクエストなのかがわからない

Aさんによる指示で、指定されたスコープがどこかがわかるコード(以下、認可コード)を添付する

  • だいたいいい感じになってきた

ゴール状態との対応がだいたい取れた

改めてゴール状態の図を眺めてみましょう

ある程度背景が「こうかな?」と想像できるようになっているかと思います。

stateに触れていなかったり、アクセストークンの発行、保存、リソースサーバーからの参照の方法を考察してなかったりとまだまだ深めたいところはありますが、技術選定やclientの実装レベルでは十分なところまで来たかと思います。

終わりがないので、ここで止めておきます。

終わりに

多分、OAuth2.0の仕組みがこうやって生まれたわけではありませんが、各ステップの誕生背景を想像すると楽しいし、理解が深まりやすいですね。少なくとも上記に挙げたような多くの問題を解決してるのだから、複雑に見えて当然だなと思います。

OAuthは全体としては認可の仕組みのはずですが、考えてみると認証の問題を解決している技術が多い印象でした。いつか気が向いたら、SSL/TLS版も作ってみたい気持ちです。

「その技術はどういう構成/仕様か」よりも「その技術は何を解決するか」に焦点を当てた書籍や記事が増えることを願っています。

Discussion