雰囲気で使っていませんか?OAuth2.0の基礎をざっくり整理してみた
「雰囲気で使っていたOAuth 2.0」の仕組みを整理する
Webサービス開発やAPI連携の実装で必ずと言っていいほど登場する OAuth 2.0。
「とりあえずライブラリを使えば動くから」と、なんとなく実装してしまっている人も多いと思います。
今回は、自身の復習も兼ねて、OAuth 2.0の基本的なフローやセキュリティの考え方、各用語の役割について整理してみたいと思います。
なお、本記事は以下の書籍を読み、手を動かしながら学んだ内容をベースにまとめています。非常に分かりやすい良書でしたので、詳しく学びたい方はぜひ手に取ってみてください。
登場人物とそれぞれの役割
OAuth 2.0のフローを理解するには、まず4人の登場人物(役割)を把握する必要があります。
-
リソースオーナー(ユーザー)
データの持ち主です。例えば「Googleフォトにある私の写真」を利用する場合、その「私」がリソースオーナーにあたります。 -
クライアント(アプリ)
ユーザーのデータを利用したいアプリケーションのことです。 -
リソースサーバー(API)
実際にデータを保持しているサーバーです。ここにあるデータへアクセスするために、クライアントはアクセストークンを提示する必要があります。 -
認可サーバー
クライアントに対して「このユーザーのデータにアクセスしてもいいですか?」と確認(認証・認可)を行い、アクセストークンを発行するサーバーです。
アクセストークンとスコープ
リソースサーバーへの通行証となるのが アクセストークン です。しかし、通行証があれば何でもできるわけではありません。そこで重要になるのが スコープ という概念です。
スコープは、そのトークンで「どこまで操作を許すか」という権限の範囲を定義します。
| スコープ名 | 権限の内容 |
|---|---|
photoslibrary.readonly |
写真の閲覧のみ許可 |
photoslibrary.appendonly |
写真の追加のみ許可 |
photoslibrary.sharing |
写真の共有を許可 |
このように権限を細分化することで、万が一トークンが漏洩した場合でも被害を最小限に抑えることができます。「最小権限の原則」を守るために、適切なスコープ設計は欠かせません。
グラントタイプ(権限の付与方式)を整理する
OAuth 2.0には、アクセストークンを発行するためのフロー(グラントタイプ)がいくつか存在します。
利用する環境やセキュリティ要件によって適切なものを選ぶ必要があります。
1. 認可コードグラント (Authorization Code Grant)
最も一般的で、現在推奨されている方式です。
Webアプリやモバイルアプリで利用されます。認可サーバーから一度「認可コード」を受け取り、それをサーバー側でアクセストークンと交換するため、セキュリティ強度が高いのが特徴です。
2. インプリシットグラント (Implicit Grant)
かつてSPA(Single Page Application)向けに使われていた、クライアントが直接アクセストークンを受け取る方式です。
しかし、URLにトークンが含まれるため漏洩リスクが高く、リフレッシュトークンも使えないなどの理由から、現在は非推奨となっています。現在はSPAであっても、後述するPKCEを併用した認可コードグラントの使用が推奨されています。
3. クライアントクレデンシャルグラント (Client Credentials Grant)
ユーザー(リソースオーナー)が介在せず、アプリ自身がAPIを利用するケースで使われます。
例えば、システム間のバッチ処理や、バックエンドサーバー同士の通信などがこれに当たります。
4. リソースオーナーパスワードクレデンシャルグラント (ROPC)
ユーザーのIDとパスワードをクライアントアプリが直接受け取り、認可サーバーに送信する方式です。
アプリ側にパスワードが渡ってしまうため、OS標準の機能や公式アプリなど、よほど信頼できるクライアント以外では非推奨です。
リフレッシュトークンとセキュリティ
アクセストークンには通常、1時間程度などの短い有効期限が設定されます。
期限が切れるたびにユーザーにログインを求めるのは利便性が悪いため、ログインなしで新しいアクセストークンを再取得するために使われるのが リフレッシュトークン です。
リフレッシュトークンは有効期限が長く設定されるため便利ですが、裏を返せば、漏洩した場合のリスクが非常に高い情報です。そのため、セキュアなストレージに保存するなど厳重な管理が求められます。
なぜPKCEが必要なのか
モバイルアプリやSPAのような「パブリッククライアント」では、client_secret(秘密鍵)を安全に管理することが困難です。その弱点を補うために導入されたのが PKCE (Proof Key for Code Exchange) です。
仕組みとしてはシンプルです。
- 認可リクエスト時に、ランダムな値から生成した
code_challengeを送信する - トークン交換時に、その元となった
code_verifierを送信する - 認可サーバー側で照合し、正当なリクエストか検証する
これにより、万が一途中で認可コードが横取りされたとしても、攻撃者は code_verifier を持っていないためアクセストークンを取得できなくなります。
現在では、モバイルアプリに限らず、WebアプリでもPKCEの利用が推奨されています。
まとめ:どのフローを選ぶべきか
ここまでの内容を踏まえると、フローの選択基準は概ね以下のようになります。
-
サーバー間通信を行いたい
👉 Client Credentials Grant -
Webアプリ / モバイルアプリ / SPA
👉 Authorization Code Grant (+ PKCE)
以前は「SPAならインプリシット」と言われていましたが、現在はセキュリティの観点から「認可コード + PKCE」がスタンダードになっています。
OAuth 2.0は奥が深く、細かい仕様まで追うと大変ですが、まずは「誰が」「何を」「どうやって」許可しているのかという基本フローを押さえることが、安全な実装への第一歩だと感じました。
Discussion