🤖

自分の理解のために OAuth2.0 での認可を Zenn の Google ログインで説明してみる

2021/01/30に公開
2

登場人物

Provider

Google や Twitter など、ユーザーに関する情報を持っているウェブサイト。

Consumer

Provider の情報を使ってアレコレするサイト。
あなたが OAuth 認証認可を使って何かウェブサイトを作りたい時、作るサイトは Consumer となります。zenn.dev も Google ログインに対応しているので Consumer です。

User

すでに Provider に情報を登録していて、Consumer のサイトをこれから使おうとしている人。

Client

User の操作側のプログラム。

OAuth 2.0

手順は以下の通り。

  1. Client が Consumer(Zenn) に、「これから OAuth を使いたい」という情報を伝えます(例えば Login with Google というボタンをクリックします)。

  2. Consumer(Zenn) は、User の情報がどの程度欲しいか(権限がどれくらい必要か)を表す scopes を決めます。また、同時に state というランダムトークンを作ります。そして、Provider(Google) への URL を、scopesstate、 そして Consumer が誰かを表す client id を埋め込んだ状態で Client に渡します。

  3. Client は、渡された URL を使って Provider(Google) にアクセスします(例えば Login with Google をクリックした後に出てくる Google の画面の URL は、前のステップで Consumer から渡された URL です)。
    この URL に埋め込まれた client id を見て、Provider(Google) は Consumer(Zenn) を判別します。OAuth を使ってアプリを作る場合、Consumer(Zenn) 側が事前に OAuth 認証を使うために Provider(Google) に登録しているので、判別できます(例えば Google であれば Google Developer Console で登録します)。
    また、URL に埋め込まれた scopes を見て、Consumer(Zenn) がどのような権限を欲しているかを確認します。Provider(Google) はそれをもとに「この Consumer(Zenn) というサイトは以下のような権限を求めていますよ」という確認画面を出します。

  4. User 側が、ログインしたり OK ボタンを押したりして同意したのを確認したら、Provider(Google) は authorization code を発行します。そして今度は Consumer(Zenn) への URL を、authorization codestate を埋め込んだ状態で Client に渡します。

  5. Client は、渡された URL を使って Consumer(Zenn) にアクセスします。Consumer(Zenn) はまずこの URL に埋め込まれたstate トークンを見て、それが以前に自分が発行したものと同じかどうかを確認します。これにより、悪意のある別のユーザーが元の User を騙ることを防ぎます。
    それから、Consumer(Zenn) は URL に埋め込まれた authorization code を、自身の client id とともに Provider(Google) に POST で送ります。Provider(Google) 側は、自分が以前に発行した authorization code に間違いないことを確認します。そして、最終的に Consumer(Zenn) に access token を返します。これで、全てのプロセスが完了します。
    Consumer(Zenn) は access token を持っていれば User が「ログイン済」であると判断し、ログイン後のページを返す処理を行うことができます。

用語の整理

  • client id: Consumer(Zenn) が Provider(Google) に、自分が誰なのかを伝えるためのもの
  • scope: Consumer(Zenn) が、自分のアプリにユーザーの情報がどのくらい必要なのかを考えて設定するもの
  • state: Consumer(Zenn) が、悪意のあるユーザーによる乗っ取り(CSRF攻撃)を防ぐために用意するもの
  • authorization code: Provider(Google) が Consumer(Zenn) の正当性を確認するために発行するもの
  • access token: ユーザーが認可済みであることを Consumer(Zenn) が確認するためのもの(Provider(Google) が発行する)

認証と認可の違いについて

認証(Authentication)は「誰であるか」を確認することで、認可(Authorization)は権限を与えることです。
OAuth でログインするというのは、あるユーザーの認可済み access token の存在をもってして、あるユーザーの認証も行うということです。なので、認証認可とまとめて呼ばれたりもします。
ですが、OAuth 自体は元々認可をするために作られたプロトコルなので、それを認証にも使ってしまうことは潜在的には危険です。実際、悪質なサイトがあるユーザーの access token を流出させたりすると、他の OAuth を認証に使っているサイトでもそのユーザーとして認証できていることになってしまいます。

Reference

https://flask-dance.readthedocs.io/en/latest/how-oauth-works.html
https://murashun.jp/article/programming/oauth2.html
https://qiita.com/sgmryk/items/0f5734a2a6991a6a1873

Discussion

ritouritou

ちょっと気になったんですが

  • 説明したいこと : OAuth 2.0での認可の流れ
  • 例 : Google でログイン
  • 認証と認可は違う

と、読者が混乱しそうな内容になっているように思えます。

アクセストークン取得までの流れを説明したい場合は、Googleログインの例を使ったとしても「この時点でアクセストークンを取得できます」「アプリケーションはユーザーの代わりにAPIアクセスできます」までで留めておくのが良さそうです。

その上で、認証用途に利用する場合は

  • アクセストークンからユーザー情報を引いてログインさせるユーザーを判別 : トークン管理によっては危険
  • GoogleはOpenID Connectにも対応しており、IDTokenという認証イベントの結果を用いてログインさせるユーザーを判別できる

という流れにすると、うまく機能を整理しながら説明できるかもしれません。

Kaito SugimotoKaito Sugimoto

読者が混乱しそうな内容になっているように思えます。

はい、おっしゃる通り、体系だった説明にはなっておりません。あくまで自分の理解のためにまとめたものです。
記事タイトルが啓蒙っぽい感じでミスリーディングだったので、変更しておきました。
(この記事を書いた時には存在に気づかなかったのですが、スクラップを使った方が良かったなぁと思っています。)