bff

フルスタックエンジニアを目指して学んだことなどを記録しています

OAuth 2.0における4つの承認フロー

OAuth 2.0に関する実装を行う機会があったので、個人的に勉強した内容をまとめました。 OAuth 2.0と一口に言っても、4つのフローが規定されており、ユースケースに応じて適切なものを使う必要があるので、ざっくりとその概要を理解できるようにまとめました。

OAuth 2.0とは

サービス上で保有しているユーザのデータについて、ユーザが第三者のアプリケーションに対してID・パスワードを渡すことなく連携することができるようにする仕組みです。 GoogleFacebookTwitterで以下のような画面で認証することで、例えばFacebook上のアプリケーションがTwitter上のデータを組み合わせてサービス提供している仕組みというとイメージしやすいと思います。 f:id:tsbkw:20190208234336p:plain

OAuth 2.0の仕様のなかでは一部認証(Authentication:誰なのか)について語っている部分もありますが、あくまでもOAuth 2.0は認可(Authorization:誰に何の権限を与えるか)の仕組みです。

OAuth 2.0の承認フローについて

OAuth 2.0では4つの承認フローが定義されています。フローの特徴とその流れについてまとめています。 ここでの説明では、以下の用語を利用しています。参考までにRFC上の用語を括弧書きしています。 * アプリ(client): OAuth 2.0を利用してサービスを提供するアプリケーション。 * サービス: アプリにデータを提供するサービス。認可サーバとリソースサーバで構成されます。      認可サーバ(authorization server): データをアプリに提供してよいか(認可)を制御するサーバ      リソースサーバ(resource server): 認可サーバの制御に基づき、自身が保有するデータをアプリに提供するサーバ。 * ユーザ(end-user/resource owner): アプリとサービス双方を利用しているユーザ。

1. Authorization Code Grant

(RFC 6749 4.1 Authorization Code Grant)https://tools.ietf.org/html/rfc6749#section-4.1で規定されているフローです。

特徴は、認可コードを一時的に取得し、それを元にアクセス・リフレッシュトークンを取得するところです。

フローは次の通りです。

  1. アプリから外部の認可サーバが提供する認可画面に遷移して、ユーザが認可(権限をアプリに渡してよいかのチェックを、サービスへのログインID・パスワードを入力して実施)を行います。
  2. 認可されると、1. の遷移時にアプリが指定したURIへ認可画面がリダイレクトしてくれるので、アプリはGETパラメータに含まれる認可コードを受け取ります。
  3. この認可コードを用いてアプリは認可サーバへアクセストークン、リフレッシュトークンの値を受け取りに行きます。(リフレッシュトークンはオプションのため、認可サーバによっては返してくれません。)
  4. 受け取ったアクセストークンを用いて、アプリはリソースサーバからデータを取得します。
  5. アクセストークンの期限が切れたらリフレッシュトークンによってアクセストークンを更新する必要があります。

認可のまえに認証を求められることが多く、client_id、client_secretを用いた認証やBasic認証が利用されます。実装の詳細は認可サービス(Google, Facebookなど)のドキュメントを参照してください。認可を利用するアプリ向けにライブラリを提供しておりその利用を推奨しているケースもあります。(例:(Google)https://developers.google.com/api-client-library/では他のAPIと同様にOAuth2向けのライブラリを言語別に提供しています)

なお、スマホアプリの場合は認可コード横取り攻撃(authorization code interception attack)の危険性があるので、PKCE(Proof Key for Code Exchange)による対策が必要です。詳細は以下の記事が詳しいですが、code_challengeのやりとりを上記フローの中に含めるものです。 (PKCE: 認可コード横取り攻撃対策のために OAuth サーバーとクライアントが実装すべきこと)https://qiita.com/TakahikoKawasaki/items/00f333c72ed96c4da659

2. Implicit Grant

(RFC 6749 Implicit Grant)https://tools.ietf.org/html/rfc6749#section-4.2で規定されているフローです。

特徴は、認可コードのやりとりをすることなくアクセストークンを取得できるためフローがシンプルなことと、リフレッシュトークンが発行されないため、有効期限が切れた際は再度アクセストークンの発行が必要になることです。 フローの中でAuthorization Code Grantとの違いを太字にしています。

  1. アプリから外部の認可サーバが提供する認可画面に遷移して、ユーザが認可を行います。
  2. 認可されると、1. の遷移時にアプリが指定したURIへ認可画面がリダイレクトしてくれるので、アプリはGETパラメータに含まれるアクセストークを受け取ります。
  3. 受け取ったアクセストークンを用いて、リソースサーバからデータを取得します。

3. Resource Owner Password Credentials Grant

(RFC 6749 4.3 Resource Owner Password Credentials Grant)https://tools.ietf.org/html/rfc6749#section-4.3で規定されているフローです。

特徴は、1. , 2. のフローではサービス側がユーザに対して認可画面を表示していたのに対し、このフローではサービス側がユーザに認可画面を表示する点です。 そのため、ユーザがサービスで利用しているID、パスワードをアプリ側が知ることができてしまい、アプリ側が信頼できない場合にこのフローを利用するのは危険です。 RFCでも1., 2. のフローが利用できないケースでのみ利用すべきとされています。

  1. アプリが認可画面を表示し、ユーザにサービスへのログインID・パスワードの入力させます。
  2. アプリは1.で受け取ったログインID、パスワードをパラメータに含むPOSTリクエストによって認可サーバへアクセストークンを要求します。
  3. 認可サーバはHTTPレスポンスによってアクセストークンをアプリに返します。(認可サーバによってはオプションでリフレッシュトークンを返します。)
  4. 受け取ったアクセストークンを用いて、アプリはリソースサーバからデータを取得します。

4. Client Credentials Grant

(RFC 6749, 4.4. Client Credentials Grant)https://tools.ietf.org/html/rfc6749#section-4.4で規定されているフローです。

特徴は、ユーザの認証を行わず、client_id、client_secretもしくはBasic認証によるアプリの認証のみが行われる点です。

  1. アプリは認可サーバに対して認証情報を送り、アクセストークンを要求します。
  2. 認可サーバは認証情報を確認し、アクセストークンを発行します。