はじめに
この記事の目的
- OAuthが必要とされる理由を、仕組みを通して理解すること
想定される読者
- OAuthという名前を初めて聞いた人
- OAuthという名前だけ知っている人
- ライブラリ等を使ってOAuthを実装した経験があってもいまいちピンと来ていない人
解説すること
- OAuthが必要な背景
- OAuthで登場する用語
- OAuthの仕組み
解説しないこと
- OAuthの具体的な実装方法
※ 何番煎じか分からないが、改めてOAuthを解説する(実践編)で解説する予定です。
前提
本記事はWebアプリケーション開発の経験がある方を前提としています。
現在「OAuth」と言った場合、一般的にはOAuth 2.0を意味します。
OAuth 1.0はリクエストごとに署名を行う必要があり、実装や運用が複雑です。
OAuth 2.0ではHTTPSを前提とすることで設計が大幅に簡素化され、
Webだけでなく、モバイルアプリやSPAなど様々な環境で統一的に利用できるようになっています。
以降、特に明示しない限り、本記事におけるOAuthはOAuth 2.0を指します。
OAuthとは何か
OAuth (2.0)はインターネットの世界に身を投じている人にとっての聖典、RFCで定義されています。
RFC 6749
RFC 6749 Abstractの直訳を見てみましょう。
少し長いですが、HTTPサービスへの限定的なアクセス取得を可能にする。OAuth 1.0を置き換えているというのがわかりますね。
OAuth 2.0 認可フレームワークは、サードパーティアプリケーションがHTTPサービスへの限定的なアクセス権を取得することを可能にします。これは、リソース所有者に代わってリソース所有者とHTTPサービス間の承認インタラクションを調整するか、サードパーティアプリケーションが自身に代わってアクセス権を取得することを許可することによって実現されます。本仕様は、RFC 5849で記述されているOAuth 1.0プロトコルを置き換え、廃止します。[STANDARDS-TRACK]
もう1つ見てみましょう。
世界の叡智の書。Wikipediaの直訳によると...
OAuthは権限の認可を行うためのオープンスタンダードである
まだピンとこない人もいるでしょうか。
最後に私なりの解釈も置いておきます
ユーザーからIDやパスワードを受け取ることなく、 GoogleやGitHubといった別サービスが保有する ユーザーの情報にアクセスする【権限をもらう】仕組み
ちょっとイメージが湧いたでしょうか。 そうだと嬉しいです。
OAuthがなぜ必要なのか
OAuthの仕組みについて詳しく探る前に、なぜOAuthが必要だったのかを確認していきましょう。
OAuthが存在する前の時代、サードパーティーアプリからGoogleやXといった、別サービスのアカウント情報を利用したり、操作したり(自動カレンダー登録とか)するにはどんな手段があったでしょうか。
思いつく限り挙げてみると以下の方法で実現できそうですね。
| 方法 | 詳細 | 問題点 |
|---|---|---|
| スクレイピング(ブラウザを操作) | サードパーティアプリはemail, passwordの2つを受け取ります。 人間が操作するのと同じように、ブラウザを操作してログイン後、ユーザー情報の取得や何かしら操作を行います。 | - サードパーティアプリにemailとpasswordを渡す必要がある。 - 実際にブラウザを操作する性質上レスポンスに時間がかかりがち。 |
| ID/Passwordを使ったAPI認証 | サードパーティアプリはemail, passwordの2つを受け取ります。受け取った認証情報を使ってAPIを叩きます。 | - サードパーティアプリにemailとpasswordを渡す必要がある。 |
| API認証 | 本来開発者が自身の情報を取得するために使用するAPIキーをユーザーに発行してもらい、サードパーティーアプリ上で登録してもらう方式 | - ユーザーに紐づく一意なAPIキーがサードパーティー側に渡る |
| 上記3つの共通する点として以下の特徴があります。 |
- 認証情報やAPIキーといった、本来第三者に渡すべきではない情報を渡す必要がある
- 性質上全権限をサードパーティーに許可することになる
上記によって様々なリスクが発生しますが、いくつか例にあげてみましょう。
- サードパーティーが悪意のあるユーザーにハックされ、ユーザーの認証情報が漏洩する
- サードパーティーが誤った操作をするとデータの削除など致命的な操作を行える
- サードパーティー自体が悪意のあるサービスだった場合アカウントを乗っ取られてしまいます。
実例を挙げてみると、10年くらい前に某SNSアプリのフォロー・フォロワー・片思い状態を可視化できるようなアプリがありました。当時私は中学生くらいでしたが、今20代後半くらいの人は覚えがあるかもしれませんね。このアプリは名目通りに使うことができたのですが、登録してしばらく経つと不正なログインや不審なemailが届くようになるという特徴がありました。 真相はわかりませんが、上記で説明した何かが起こっていた可能性はあると思います。 これ以外にもサードパーティー製アプリの使用によって、アカウントが乗っ取られてしまう事例は多々ありました。アプリ自体は普通に使えるというのが厄介で、裏では情報の売買がされてしまうのが怖いところですね。
OAuthが解決すること
- パスワードなどをサードパーティーに渡すことなく、 GoogleやGitHubといった別サービスが保有する ユーザーの情報にアクセスする許可を与えることができる
- 許可する情報/操作を細かく選択できる
加えて、OAuth 2.0が一般化することで、外部サービスにアクセスするための手順の共通化が進みます。 これはエンジニアにとっては開発の効率性を上げ、ユーザーにとってはよくみるインターフェイスで安心感を与えます。
いいことばかりですね。
OAuthの用語
ここでOAuthの仕組みを解説する前に用語の整理をしておきます
| 用語 | 説明 |
|---|---|
| リソースオーナー | 情報に紐づく本人です。 GoogleとOAuth連携する場合、リソースオーナーはGooleアカウントを作成したユーザーです。 |
| クライアント | ユーザーに変わって認可を受けたいアプリ(サードパーティーアプリ) |
| リソースサーバー | 実際のデータを持っているAPIサーバー (Google) |
| 認可サーバー | クライアントに対して認可を与えて良いか判断するサーバー・トークンの発行をする |
| アクセストークン | 認可サーバーが発行するアクセストークンで有効期限とScopeがある |
| リフレッシュトークン | アクセストークンを再取得するためのトークン |
| スコープ | 認可する内容を示す権限の範囲 (名前, 生年月日のREADのみ許可など) |
| 認可コード | 認可フローの中で一時的に発行されるコード |
認可の流れ
ここでは、OAuth 2.0で最も一般的に使われている「Authorization Code Flow」を例に、認可の流れを説明します。
登場する要素
Googleを例に簡易版の用語を再度掲載します。
- リソースオーナー:ユーザー
- クライアント:サードパーティアプリ
- 認可サーバー:Googleの認可サーバー
- リソースサーバー:GoogleのAPI
図にすると以下のようになります。
認可の流れ
ユーザーの操作も含めてより詳細に説明すると以下のような流れになっています。
- ユーザーがクライアント上で操作を行う(ログインボタンを押す)
- クライアントはユーザーを認可サーバーへリダイレクトする(ログインページ表示)
- ユーザーは認可サーバーでログインし、権限付与に同意する
- この際許可するスコープがユーザーには明示されます。
- 認可サーバーは認可コードを付与してクライアントへリダイレクトする
- クライアントは認可コードを使ってアクセストークンを要求する
- 認可サーバーはアクセストークンを発行する
- クライアントはアクセストークンを使ってAPIへアクセスする
補足
認可コードとアクセストークン
上記流れを見た人はなぜ4で直接アクセストークンを返さないのかと疑問に思った方もいるかと思います。
これは4でリダイレクトする際にGETリクエストを使用する関係上、access tokenがリクエストのURLやブラウザの履歴、キャッシュに残る可能性があり危険だからです。
使い捨ての認可コードでリダイレクト(GET)後、アクセストークンのリクエスト(POST)を行うことでセキュアになっています。
OAuth2.0はログインの仕組みではない
OAuth 2.0は「ログインの仕組み」ではなく、「第三者に限定的な権限を安全に委譲する仕組み」です。
ここは間違えないようにしましょう。
RFC OAuth 2.0の範囲について
認可の流れを紹介しましたが、1番と7番はあくまで副次的な要素です。
OAuth 2.0は認可サーバーがリクエストを受けて、Access Tokenを発行するまでのの手順を規定しているので、2番から6番がOAuthの仕組みになります。
まとめ
いかがだったでしょうか。 OAuth登場前に抱えていた問題、OAuthが解決したことを踏まえて、理解が深まっていると幸いです。
次の記事、実践編では、実際にOAuthの実装をする予定です。
普段の開発では上記ステップを自力で1から開発することはなく、便利なライブラリを使うことが一般的です。 上記の流れを理解した上で、ライブラリがどこからどこまでを担当してくれているのかを把握すると、単なるコピペではなく、ライブラリの中で何が行われているのか理解しやすくなると思います。
