OAuthの認可の流れ

武井宜行氏:次に、OAuthの登場人物を説明します。(スライドを指して)いろいろ書いてありますが、OAuthの登場人物をざっくり言うと、認可サーバー、リソースサーバー、クライアント、リソースオーナーです。

さっきの図をベースに説明すると、リソースオーナーはAさんにあたる、Facebookの中の投稿の一覧を保有している人です。認可サーバーは、Aさんを認証する人、認証を提供するサーバーです。リソースサーバーは、AさんがFacebookの中で持っている投稿一覧を保持しているサーバーです。クライアントは、認可サーバーからアクセストークンを受け取るサーバーのことです。

今後の説明でどうしてもリソースオーナー、認可サーバー、リソースサーバー、クライアントという言い方をするので、ここでこれらの関係を覚えてほしいと思い、説明しました。

(スライドを指して)ここからの説明の都合上、OAuthをざっくり説明した認可コードのフローを1枚のスライドにまとめてみました。1番で認可サーバー兼リソースサーバーに認可リクエストを送って、2番でパスワード認証をしてします。そして、認可コードが渡されて、クライアントから認可コードを送ってアクセストークンを取得し、アクセストークンを基にリソースサーバーに接続して、リソースを取得します。

先ほどは認可サーバーとリソースサーバーが同じでしたが、実はこれらは分かれる場合もあるんです。(スライドを指して)分かれた場合のシーケンスはこうなります。認可サーバーでいろいろ認可コードなどを認証して、アクセストークンを渡して別のリソースサーバー、アクセストークンを渡す先はまったく別のサーバーということがあります。

なぜこういうことがあるかというと、最近はIDaaSというものが流行っています。「IDaaSって何?」と思うでしょうが、認証・認可のみに特化したSaaS型のマネージドサービスです。Facebookは認証・認可もやって、投稿一覧を提供したり、いろいろなコンテンツを提供しますが、IDaaSは認証しか提供しません。

IDaaSは、ワンタイムパスワードや証明書認証などの認証に特化したサービスなので、すごくいろいろな認証方法を提供しているんです。代表的なものでは、Microsoftが提供するAzure Active Directoryや、Auth0あたりが有名です。

これはどういう時に使うかというと、例えば自社開発のオンラインストレージサービスを開始したいとします。でも、自社開発のオンラインストレージは、認証サービスを作り込むのがすごく大変だと思うんです。多要素認証、ワンタイムパスワード認証、証明書認証。そういうものを作り込むのはメチャクチャ大変じゃないですか。

なので、そういうところはIDaaSと言われるAzure Active DirectoryやAuth0に任せてしまおう。餅は餅屋ということで、認証・認可はIDaaSに任せてしまえば、自分はオンラインストレージの開発に専念できる。最近よくこういう構成が取られるんです。だから認証・認可とリソースサーバーが分かれることはよくあります。

アクセストークン取得のための認可コードフロー

次に、いろいろなフローを説明します。アクセストークンを取得するためにはいろいろあります。その代表的なフローを、今回いくつか説明したいと思います。

説明するのは、認可コードフローとImplicitフローとクライアントクレデンシャルズフローです。

認可コードフローは、先ほどOAuthをざっくり説明したところのフローで、あれがまさしく認可コードフローになります。認可コードフローは、よくあるWebアプリと、ほかにリソースサーバーが登場した時に使います。

アクセストークン取得のためのImplicitフロー

では、Implicitフローはどういう時に使うかというと、例えばネイティブアプリや、よくあるスマホ内のアプリ、ブラウザー上のJavaScriptで動くアプリといった、手元のアプリが直接Facebookの認可サーバーやリソースサーバーに通信する場合に使います。

(スライドを指して)先ほどの認可コードフローと同じように、シーケンス図を説明します。Aさんはリソースオーナーです。そしてAさんのスマホ内のアプリ、これが今回のクライアントです。これが直接アクセストークンを受け取ります。そして、このAさんのスマホ内のアプリの開発者がにいます。これは先ほどの認可コードフローと同じですが、FacebookにOAuth認証をしたいという申請をします。

そうすると、クライアントIDとクライアントシークレット、利用サービス、アクセストークンに付与するサービスが発行されるのは同じです。この手順について追加説明をしますが、Implicitフローではクライアント(この場合だとスマホアプリ)には、クライアントIDやクライアントシークレットを保存しません。

なぜなら、Implicitフローの場合はクライアントであるスマホに、リソースオーナーであるAさんが簡単にアクセスできてしまうからです。クライアントIDとクライアントシークレットは、かなり強力な権限を持っています。そのため、クライアントIDとクライアントシークレットを認可コードフローの時みたいに、直接クライアントの中に保存はしません。

ではどうやるかというと、スマホ内の埋め込みブラウザーが、Facebookのログイン画面にアクセスします。最近よくスマホ内に埋め込みのブラウザーがあると思いますがが、そこからFacebookの認証画面にアクセスします。

手順について説明を追加します。(スライドを指して)Facebookの認証画面にアクセスするためのURLはスライドのとおりです。この書式は、OAuthの仕様である程度決まっています。

一般的にこのURLは認可エンドポイントと言われています。この「〇〇/authorize」というのは、だいたいリソースサーバー、FacebookやAzure Active Directoryごとに決まっています。

クエリパラメータでつけるresponse_typeは、指定する値によって認可コードフローが発動するのか、Implicitフローが発動するのか、クライアントクレデンシャルズフローが発動するのかが決まります。認可コードフローの場合はcodeとしますが、今回はImplicitフローなのでtokenと入れます。

Facebookの認証サーバーでの認証が完了すると、事前にFacebookで設定したリダイレクトURLにリダイレクトされます。このリダイレクトURLの中に、ハッシュフラグメントとしてアクセストークンがついてきます。これが認可コードフローと違うところです。

認可コードフローでは認可コードがついてきましたが、ここではダイレクトにクライアントのスマホのネイティブアプリにアクセストークンを発行したいので、リダイレクトのURLのハッシュフラグメントにアクセストークンがついてきます。

このアクセストークンを解析して、自身のスマホのアプリの中にアクセストークンを保存します。

スマホのアプリはFacebookにアクセストークンを送るとともに、投稿の一覧を表示する。これがImplicitフローの流れです。

インプリシットフローのポイントは以下のとおりです。先ほど説明したように、認可コードフローとは異なり、認可サーバーの認証完了なレスポンスでダイレクトにアクセストークンを受け取ります。

やはりアクセストークンがそのクライアントの認可サーバーの中で流れる、パブリック上のネットワークに流れるので、けっこう漏洩のリスクが高いのが欠点です。mplicitフローにはいくつかの脆弱性があるため、今は非推奨です。最近は、スマホアプリのようなネイティブのアプリでも、認可コードフローを用いるのが普通になっています。

アクセストークン取得のためのクライアントクレデンシャルズフロー

次に、クライアントクレデンシャルズフローですが、主にバッチ処理みたいなプログラムで用います。(スライドを指して)ここで登場している人物はバッチの開発者、Facebook、バッチ処理サーバーです。バッチ処理サーバーの中のバッチのプログラムが、Facebookに接続して投稿の一覧を取得するようなユースケースを考えてみます。

バッチの開発者はFacebookに対して、「OAuthを使いたい」という申請をします。

そうすると、バッチの開発者はFacebookからクライアントIDとクライアントシークレットをもらい、それらをバッチ処理サーバーに登録します。

バッチサーバーのバッチプログラムは、クライアントIDとクライアントシークレットを渡して、アクセストークンを要求します。

認可サーバーがクライアントIDとクライアントシークレットが正しいものであることを確認できたら、バッチ処理サーバーにアクセストークンを返すという流れです。

(スライドを指して)クライアントクレデンシャルズフローのポイントは以下のとおりです。クライアントIDとクライアントシークレットで、アクセストークンを取得します。バッチ処理みたいなブラウザーが介在しない場合は、認可コードフローやImplicitフローは当てはまらないので、こういうフローを用います。クライアントIDとクライアントシークレットはかなり強い権限を持つので、普通は信頼できる相手にしか渡しません。

この場合、バッチの開発者は自身が管理しているサーバーなので、クライアントIDとクライアントシークレットを渡すことは、特に問題にならないという感じです。

今回は、認可コードフローやImplicitフローによって、トークンを安全に取得できます、という話をしました。

ここでもう1つ、クライアントクレデンシャルズフローではなくリソースオーナーパスワードクレデンシャルズフローというものを説明しようかと思いましたが、時間があまりないので割愛します。

(次回に続く)