- 公開日
- 最終更新日
OAuthをざっくり理解する
この記事を共有する

はじめに
パーソルサーバーワークスの嶋田です。
今回はRFC6749に基づいたOAuthの技術仕様についてふれていきたいと思います。
すべてを網羅すると相当なボリュームになるため、主観ベースでOAuthとは何たるかをなんとなくわかる状態に持っていくことを目標とします。
※技術を蔑ろにする意図はございませんので、Partをいくつかに分けて徐々に掘り下げようと計画しています
ゴールは、本ブログを通じてOAuthで標準的な Authorization Code Grant の流れ・仕組みを理解することとします。
OAuthとは
OAuth(Open Authorization)は、ユーザーのパスワードを共有せずに、サードパーティのアプリケーションへ限定的な認可をするためのフレームワークです。
認可プロトコルとも呼ばれ、WebサービスやAPIアクセスに利活用されている技術です。
本ブログで OAuth と言った場合は、 OAuth 2.0 を指します。
現在はRFC9700までドキュメント更改が進んでいます。
この記事ではOAuthの基本を抑えるために、RFC6749に記述されているトピックを私なりに解釈、記述したものです。
事実を歪曲させる意図はございませんので、原文も積極的に引用いたします。
実際のユースケース
オープンバンキング
インターネット決済系のAPIなど。
例えば、クレジットカード決済を行う際、銀行系システムにリダイレクトされる。
政府系システム
SNS
別サービスの認証情報を使って、サービスにログインできる仕組みとして活用。
例えば、XにはGoogleアカウントを使ってのログインも可能。
この記事で取り扱う用語集
アクセストークン
- 認可されたリソースにアクセスする際に使うトークン
- トークンは、クライアントに対して、認可サーバーから払い出される
- トークンを使うことで、トークンに紐づけられた認可を享受できる
リフレッシュトークン
- アクセストークンが有効期限切れになった際に新しいアクセストークンを取得するために使うトークン
- リソースサーバーには送信しない
認可エンドポイント
- クライアントがリソースオーナーから認可を得るために使用されるエンドポイント
- クライアントから希望する認可グラントタイプをクエリパラメータresponse_typeに設定してリクエストを送る
トークンエンドポイント
- 認可グラントに応じてアクセストークンを発行するエンドポイント
- リフレッシュトークンを使ったアクセストークン更新に使うエンドポイント
認可グラント
- アクセストークンを取得するために使う4種類の方式の総称
- 4つのうち認可コードグラント(authorization code)が主流であり、最もセキュア
- どの認可グランドを採用するかは、クライアントタイプに基づいて決定する
- クライアントタイプは2つにわけられる
- コンフィデンシャル
- パブリック
コンフィデンシャルクライアント
- バックエンドなどのクライアント
クレデンシャルの機密性を保持できるクライアント(例えば、クライアント・クレデンシャルへの アクセスが制限された安全なサーバー上に実装されたクライアント)、または他の手段を使用した安全なクライアント認証が可能なクライアント
パブリッククライアント
- Webブラウザやスマホアプリなどのクライアント
クレデンシャルの機密性を維持できないクライアント(例えば、インストールされたネイティブアプリケーショ ンやウェブブラウザベースのアプリケーションなど、リソース所有者が使用するデバイスで実行するクライアント)、 および他の手段による安全なクライアント認証ができないクライアント。
クライアント識別子
- 認証サーバーが発行するID
- クライアントごとに認証サーバーで発行する
- 認可サーバーにとってユニーク
保護されたリソース
- リソースサーバーによって管理されているリソース
リソースオーナー
保護されたリソースにアクセスを許可できるエンティティ
リソースオーナーが個人である場合、エンドユーザーと呼ばれる
リソースサーバー
- Google, X, Instagramなどのサービス
保護されたリソースをホストするサーバーは、アクセストークンを使用して保護されたリソースの要求を受け入れ、応答することができる
クライアント
- 認可リクエストを送信するエンティティ
- フロントエンドアプリ・バックエンドアプリ・スマホアプリなど
リソース所有者に代わって、その承認を得て、保護されたリソース要求を行うアプリケーション。「クライアント」という用語は、特定の実装特性(例えば、アプリケーションがサーバー、デスクトップ、または他のデバイス上で実行されるかどうか)を意味しない
認可サーバー
- OAuthで認可を管理するサーバー
- AWSで言えばCognitoのこと、その他にもOktaやGoogle、Xなど様々なサービスがなりうる
サーバーは、リソース所有者の認証に成功し、認可を得た後、クライアントにアクセストークンを発行する
オープンダイレクト
ユーザーのブラウザを、クエリパラメータから得られる任意のURIに転送する、ウェブサーバー上のエンドポイントのこと
OAuthが解決する課題
※本ブログで取り扱う引用枠は、すべてRFC6749に記述されている文書に翻訳したものです
1. パスワードを複数のサービスで所持しなくて良い
OAuthが無いと、サービスごとにパスワードを設定・管理する必要が出てきます。
パスワードは本来一か所で集中管理したいものです。
複数箇所で同じパスワードを保持することは、攻撃者からすると的が増えることになります。
例えば、盗難やパスワードの平文保存によるセキュリティリスクが高まります。
OAuthを使うことでサービスごとのパスワード管理が不要になり、一元的な認可が可能になります。
サードパーティのアプリケーションは、将来使用するためにリソース所有者の認証情報を保存する必要があり、通常はパスワードが平文で保存される。
2. 過剰な権限・期間の認可をしなくて良い
OAuthが無いと、フルアクセスを与えるか、何も与えないかの2択を迫られます。
このときの問題点としては、不必要な権限まで与えざるをえないことです。
例えば、ユーザーは写真共有サービスに保存されている保護されたリソース(写真)を、印刷サービス(クライアント)にアクセス許可をしたい場合、印刷サービスにログインパスワードの情報を保持する必要があったらどうなるでしょうか。
印刷サービスは私の写真共有サービスアカウントの全権を持つことになります。
全権には、不必要な権限も含まれます。
例えば、写真共有サービスに登録されている私のデータを閲覧・操作可能になります。
以下のようなものがデータに該当します。
- 住所
- 生年月日
- 非公開の写真データ
- クレジットカード情報(サブスクに利用)
パスワードをもっていることで、いつでも、好きな時に、認可が行えることになります。
ユーザーが利用をやめた後もデータの取得や操作をし続けられることになります。
OAuthは認可の有効期限を設定できるため、無期限でアクセスを許可するリスクも回避できます。
OAuthは、こうした行き過ぎた認可による問題を解決してくれます。
サードパーティのアプリケーションは、リソース所有者の保護されたリソースに過度に広範にアクセスするようになり、リソース所有者は、リソースの限られたサブセットへの期間やアクセスを制限する能力を失う。
3. サービスごとに認可の制御ができる
パスワードを使っている場合、複数のサービスをまたがった認可を個別に制御することはできません。
例えば、A, B, Cのサービスが、写真共有サービスと連携していた場合において、Aのクレデンシャルのみ無効化したくなったとします。
無効化したい理由として今回は、サービスAがセキュリティ侵害を受けたものと想定します。
この場合、サービスAでパスワードが漏洩したかもしれないので、パスワード変更が必要です。
結果、影響範囲がA, B, Cのサービス全てに波及します。
OAuthを使えば、サービスごとにクレデンシャルの無効化が実現できます。
補足として、サービスごとの認可は、例えばユーザーを連携サービスごとに払い出すなど技術的にはできますが、のちのスケーラビリティを考えると現実的ではないでしょう。
リソース所有者は、すべてのサードパーティへのアクセスを取り消すことなく、個々のサードパーティへのアクセスを取り消すことはできず、サードパーティのパスワードを変更することによって、そうしなければならない。
4. 他サービスが侵害されても、被害を最小限に抑えられる
サービスがクラッキングされてパスワードが流出すると、すべてのデータにアクセスされるリスクがあります。
例えば写真共有サービスのパスワードを他サービスに保持しておいて、パスワードが漏洩した場合、写真共有サービスはセキュリティ侵害のリスクにさらされることになります。
OAuthでは、万が一連携先の他サービスが侵害された場合は、対象のサービスのみ無効化できます。
サードパーティ製アプリケーションの侵害は、エンドユーザーのパスワードと、そのパスワードによって保護されているすべてのデータの侵害につながります。
その他
上記のように、パスワードを取り扱うことそのものにリスクがあるといえます。
パスワードにはセキュリティ上の弱点があるにもかかわらず、サーバーはパスワード認証をサポートする必要がある。
OAuthでは、クライアントはパスワードの代わりにアクセストークンを扱います。
なお、認可サーバーとリソースサーバーは同一サーバーか、責務を分けて別々にするかは、定められていいません。
仕組み
以下に RFC6749 に記載されている、OAuth(認可プロトコル)の流れを、引用します。
+--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | | | Owner | | |<-(B)-- Authorization Grant ---| | | | +---------------+ | | | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client | | Server | | |<-(D)----- Access Token -------| | | | +---------------+ | | | | +---------------+ | |--(E)----- Access Token ------>| Resource | | | | Server | | |<-(F)--- Protected Resource ---| | +--------+ +---------------+
仕組み を、「Instagramのような写真共有サービスに、写真をアップロードしている私が、印刷サービスに写真を連携して印刷する」シナリオで考えてみます。
このシナリオにおいて、仕組みが示す各エンティティは以下のように定義できます。
Client
印刷サービスのことです。
今回は、写真共有サービスに写真を譲渡してもらう必要があります。
必要な認可をしてもらわないと、写真を印刷できません。
Resource Owner
写真をアップロードしている私です。
リソースとは写真のことで、そのオーナーは私です。
Authorization Server
写真共有サービス認証のことです。
例えば、Xにログインする際にGoogleかAppleの情報でログインが可能です。
今回は、印刷サービスで写真を印刷する際に、写真共有サービスの情報でログインを求められています。
Resource Server
写真共有サービスのことです。
私の写真は、写真共有サービスにアップロードしています。
A: Authorization Request
Client は Resource Owner に認可を要求します。
本フローは簡略化されており、 Client から Resource Owner に対して直接認可要求していますが、 Authorization Server を仲介として間接的に行うことが望ましいとされています。
認可要求は、(図示のように)リソース所有者に直接行うこともできるが、認可サーバーを仲介として間接的に行うことが望ましい
B, C: Authorization Grant
Client は認可グラントをレスポンスとして受け取ります。
認可グラントとは、 Resource Owner の認可を表すクレデンシャルのことを指します。
Client は認可グラントをリクエストとして Authorization Server に送ります。
補足ですが、認可グラントには4種類のタイプが存在します。
- authorization code
- implicit
- resource owner password credentials
- client credentials
なお、OAuth / OIDCともに authorization code の利用を推奨します。
D, E: Access Token
認可グラントの検証に Authorization Server が成功したら Access Token が Client にレスポンスとして返ってきます。
Access Token を使って、何が認可されているのかは Authorization Server によって定義されています。
Client のリクエスト時に、写真共有サービスの写真アクセスを認可してもらう用に、Access Token を送信します。
F: Protected Resource
Resource Server はアクセストークンを検証して、有効であればリクエストに応えます。
Authorization Code Grant
仕組みを理解したところで RFC6749 に記載されている標準的なフロー Authorization Code Grant の流れを、以下に引用します。
Authorization Code Grant をはじめるにあたって、認可エンドポイントに送るGETリクエストのクエリパラメータとして、response_type に code を指定する必要があります。
※その他クエリパラメータとして、 client_id / redirect_uri などもありますが、ここでは割愛
+----------+ | Resource | | Owner | | | +----------+ ^ | (B) +----|-----+ Client Identifier +---------------+ | -+----(A)-- & Redirection URI ---->| | | User- | | Authorization | | Agent -+----(B)-- User authenticates --->| Server | | | | | | -+----(C)-- Authorization Code ---<| | +-|----|---+ +---------------+ | | ^ v (A) (C) | | | | | | ^ v | | +---------+ | | | |>---(D)-- Authorization Code ---------' | | Client | & Redirection URI | | | | | |<---(E)----- Access Token -------------------' +---------+ (w/ Optional Refresh Token)
改めて、「Instagramのような写真共有サービスに、写真をアップロードしている私が、印刷サービスに写真を連携して印刷する」シナリオで考えてみます。
各エンティティの実態は先に述べたものとかわりはないです。
User-Agent はChromeやFirefoxなどのブラウザです。
なお、各キーワードは以下のように読み替えられます。
キーワード | 図上のエンティティ |
---|---|
写真共有サービス | Authorization Server |
印刷サービス | Client |
私 | Resource Owner |
ブラウザ | User-Agent |
A: Client Identifier & Redirection URI
Client は、Resource Owner が User-Agent 越しに印刷対象の写真を選択した後、HTTP 302リダイレクトレスポンスを発行し、そのLocationヘッダにリダイレクトURIおよび必要なクエリパラメータ(client_id / scope / state など)を含めます。
これにより、User-Agent は自動的にそのURIへアクセスし、Authorization Server(認可エンドポイント)にリクエストを送信します。
※リダイレクトリクエストに含まれるredirect_uriは、事前に Authorization Server で登録しているURIと一致する必要があります。
クエリパラメータ | 用途 |
---|---|
client_id | Authorization Serverに登録済のクライアントを識別するためのID |
scope | 認可の範囲を示す |
state | 認可コードによるなりすまし防止に使われる |
Redirection URIについて補足
この仕様では、クライアントまたは認可サーバーがリソース所有者のユーザーエージェントを別の宛先に誘導する、HTTPリダイレクトを多用する。この仕様の例では HTTP 302 ステータスコードの使用を示していますが、このリダイレクトを達成するためにユーザエージェントを通して利用可能な他のどのような方法でも許可され、実装の詳細であると見なされます
B: User authenticates
Resource Ownerは、認証画面でIDやパスワードを入力して、Authorization Server に認証をかけます。
Authorization Server は入力されたクレデンシャルを検証します。
C: Authorization Code
認可コード(authorization code) が User-Agent にレスポンスとして返ってきています。 認可コード をリクエストのクエリパラメータに含んで、User-Agent がリダイレクトURIを開きます。
※認可コードは短い有効期限を設けることがMUSTとされています
漏洩のリスクを軽減するために、認可コードは発行後すぐに失効しなければならない(MUST)
認可コードの有効期限は最大10分が推奨される(RECOMMENDED)
認可コードが複数回使用された場合、認可サーバーはリクエストを拒否しなければならず(MUST)
D: Authorization Code & Redirection URI
受け取った認可コードを Authorization Server(トークンエンドポイント) にPOSTリクエストで送ります。
なお、POSTリクエストには client_secret が必要です。
client_secret とは、Authorization Server 側で Client を登録した際に併せて発行される値です。
E: Access Token(w/ Optional Refresh Token)
Authorization Server(トークンエンドポイント) が認可コードを検証して問題がなければ、Client にAccess Token Refresh Token を返却します。Refresh Token を返すかどうかはオプションです。
その後
アクセストークンを使って認可を検証し、写真を印刷サービスでプリントできるようになります。
おわりに
以上で、Authorization Code Grant フローを使った認証認可の流れ・仕組みの説明を終えます。
本ブログの読者に貢献できれば幸いです。
本ブログに掲載の構成図は、全てRFCドキュメントから引用しております。
長文にお付き合いいただきまして、ありがとうございました。
お疲れさまでした。
この記事は私が書きました
嶋田 龍登
記事一覧インフラからアプリのことまでなんでもやりたい、フルスタックを目指すエンジニア
