Edited at

OAuth 2.0 認証のクライアントを作る時の注意点

More than 3 years have passed since last update.


OAuth 2.0 の基本

OAuth 2.0 1 を一言でまとめると、プログラムがウェブサービス上にあるユーザ所有のリソースにアクセスするための認証フレームワークです。

クライアントプログラムの接続開始から認証完了の流れは大体このようになっています。


  1. プログラムがウェブサービスの認証サーバに自分のクライアント情報を知らせる

  2. 認証サーバがユーザにログインしてもらって、プログラムのアクセスを許可するかをユーザに確認する

  3. ユーザがアクセスを許可したら、認証サーバがアクセスするためのトーケンをプログラムに返す

  4. プログラムがトークンを使ってウェブサービスのリソースサーバにアクセスする

OAuth 自体はあくまでも認証フレームワークなので、それぞれのステップは必須な処理以外にオプションとなっている部分が多いです。2

そのため、サービスプロバイダーによってサーバ側の実装が異なるので、なんでも繋がる汎用的なクライアントを作るのはかなり面倒です。

以下では実装時の注意点を(独断と偏見で)ピックアップして説明していきます。


遠足の前:バナナはおやつなのか?

OAuth 2.0 の接続開始前、事前にサービスプロバイダーにクライアントの情報を知らせる必要があります。

クライアント情報を動的に登録や変更する標準はまだ実用化されていなくい3ので、サービス側での設定が必要となります。

そこで気をつけなければならないのは、クライアントがどのような物に対して、どのような操作を行うかです。

単一のサービスをホストしているプロバイダー(例えば課題管理システムのJIRA)の場合、

対象となるリソースは自明的なので、CRUD の制御は API のエンドポイントで行うことになります。

しかし、複数のサービスをホストしているプロバイダーの場合(例えばGoogle)、サービスやリソースごとに API を用意することが一般的です。

クライアント情報を登録する際に、API も設定しておく必要があります。

リソースに対する CRUD 権限の制限は認証時に scope で明示的に指定することになるので、scope と API が一致しないと認証が失敗してしまいます。

小学生の遠足をイメージすれば分かりやすいと思います。

かの永遠のテーマ「バナナはおやつに入りますか?」のように、気になる「バナナ」(リソースに対する操作)が「おやつ」(API)に含まれるかどうかを事前にはっきりさせておくのはとても大事です。


外野からの送球:ホームに届かないけど…?

OAuth 2.0 の認証中、ユーザを含めて、登場人物の間には何回かの情報交換を行っています。

ユーザがログインしたかどうか、もしログインしたとしたらどのアカウントを使ったか、これらの情報は認証サーバの方しか把握できません。

これの情報は認可コードに集約されて、なんらかの手段でクライアントに送らなければなりません。

認証サーバが認可コードをクライアントに返す手段として、事前に登録された redirect_uri に返送するが一般的です。

そこで気をつけなければならないのは、返送先がどこまで細かく指定できるかと、受け取れるもののいる場所を返送先として指定できるかです。

特に、ネイティブアプリケーションの場合、受け口が存在していない状況もありうるので、注意が必要です。

受け口があったとしても、グローバルIPがあるかどうか、どのポートを使用しているか、その受け口を指定できるかどうかもとても重要です。

ウェブアプリケーションの場合、制限は比較的に少ないですが、パスとポート周りはやはり要注意です。

外野(認証サーバ)からの送球がホーム(クライアント)に届どかないなら、中継(リダイレクト)すれば問題無いですが、受け取れないところにでも投げられたら困りますよね…


ス○バにて:使い捨てカップ?それともマイタンブラー?

OAuth 2.0 認証完了後に発行されたアクセストークンは、一定期間経過すると無効になります。

そのあとにまた同じリソースをアクセスしたい場合は新しいアクセストークンを再発行しなければなりません。

再発行する際、もしリフレッシュトークンを持っていれば、手順はリフレッシュトークンとアクセストークンの引き換えになります。

その場合、ユーザの認可を取りなおす手間を省けることができます。

しかし、リフレッシュトークンのの扱いもサービスプロバイダによって違っていて、大きく分けると


  • リフレッシュトークンを発行しない(例えばDropbox)

  • リフレッシュトークンは一回限り有効、または一定期間内有効(例えばBox)

  • リフレッシュトークンは無効化されるまでずっと有効(例えばGoogle)

の3つのパターンがあります。

したがって、リフレッシュトークンにつては、サポートしているかどうかサポートしているなら、いつまで使えるかを意識しなければなりません。

サポートしない場合はユーザに手間をかけないように、アクセストークン再発行フローを工夫する必要があります。

サポートする場合は、リフレッシュトークンの有効期限に合わせた、適切なトークン保持と再発行の仕組みが必要になります(特に長期間有効なものは要注意)。

ス○バでのマイタンブラー(リフレッシュトークン)を利用すると少しお得になりますが、適切な衛生管理(セキュアなトークン保持)が必要です。


まとめ

OAuth 2.0 のクライアントを作る時に、注意したほうがいい点を覚えやすい(?)ように、適当な比喩で書き留めました。

かなり適当な比喩なので、やはり標準ドキュメントを目を通して頂きたいです…





  1. RFC 6749: The OAuth 2.0 Authorization Framework. 日本語訳はこちらです。 



  2. あくまでも個人的な意見ですが、ルーティングプロトコルとかと比べると、実装側に委ねる部分が多い気がします。 



  3. RFC 7592: OAuth 2.0 Dynamic Client Registration Management Protocol. 現在はまだ実験段階です。