メインコンテンツまでスキップ

OAuth

Overview​

OAuthはプロトコルのひとつ。
OAuth = 認可(権限の認可:行動やリソースの許可をすること)
権限の認可を行うオープンスタンダードライブラリ。

OAuth 2.0は、あくまで鍵を受け渡すための安全な手順(プロトコル)
この手順を完了して手に入るのは、「アクセストークン」という名前の「魔法の鍵」だけ。

ヒント

OAuth 2.0 だけの場合: 「鍵(アクセストークン)」を渡すだけ。その鍵で何ができるかは別問題。

OIDC (Googleログインなど): その鍵と一緒に「身分証(IDトークン = JWT)」を渡す。「この人は誰々ですよ」という証明書が付いてくる。

備考

このOAuthは前述のとおりアクセストークンを発行する仕組みであって、認証については定められていない。
認証に必要なユーザー情報などの取得については決まっていない。

このOAuthを拡張しユーザー情報の取得についてなどを標準化したのが OpenID Connect

OAuth 2.0単体で「できること」​

OAuth 2.0は、あくまで鍵を受け渡すための安全な手順(プロトコル)
この手順を完了して手に入るのは、アクセストークンという名前の「魔法の鍵」だけ。

この鍵を使ってできることは、以下の通り。

  1. リソースへのアクセス 「Googleドライブのファイルを読み取る」「X(旧Twitter)でポストを投稿する」といった、具体的な**アクション(動作)**を許可された範囲内で行える
  2. 権限の限定(Scope) 「この鍵は『読み取り』はできるけど『削除』はできないよ」という制限をかけられる

なぜ「誰であるか」が「別問題」なのか?​

OAuth 2.0の鍵(アクセストークン)は誰が持っているかを証明するものではない。

  • OAuth 2.0(認可)の鍵
    • 例えるなら、ホテルの部屋のカードキー
    • フロントで「誰か」を確認した後に渡されますが、その鍵自体には「宿泊者の名前」や「住所」は書いてない。そのため鍵を持っている人が、その部屋に「入れる(認可)」だけ
  • OIDC(認証)のIDトークン
    • 例えるならホテルの宿泊証明書(顔写真付き)
    • 鍵と一緒に「この人はxxxの〇〇さんですよ」というプロフィール情報そのものを渡す
注記

OAuth2.0だけで問題なこと 鍵(アクセストークン)を渡されたShopifyが「よし、鍵があるからAPIを叩いてデータを取ろう!」とするのは良いが、**「ところで、この鍵の持ち主は誰(どのユーザー)なの?」**と聞き返さなければならない状態これが問題

連携で「OAuth 2.0だけ」だと困る理由

もし今回のShopify連携を「OAuth 2.0だけ」で行おうとするとShopifyがxxxから「鍵(アクセストークン)」をもらう

Shopify:「鍵はもらった。でも、この人はどのメールアドレスの人? 誰としてログインさせればいいの?」 Shopify:「もう一度、この鍵を使ってIdPの『プロフィール取得API』を叩いて、ユーザー情報を聞き出さなきゃ…」 このように、「鍵をもらう手順」と「誰かを確認する手順」がバラバラになってしまいます。 これを「一発で、鍵と一緒に身分証(IDトークン)も渡そうぜ!」と決めたのが OIDC(OpenID Connect)

OAuth 2.0 における同意の役割​

認可(Authorization)の承諾​

OAuth 2.0 は「権限(Capability)」を委譲するための仕組み。
「誰か」を特定する前であっても、「このアプリに私の代わりにXXをさせる」という行為には、必ずユーザーの明示的な同意が必要。

スコープ(Scope)の重要性​

同意画面に表示される内容は、リクエストされた scope に依存する。

  • OAuth 2.0 の場合: write:products, read:orders などの「アクション」
  • OIDC の場合: email, profile などの「属性」

結論​

OAuth 2.0 でも OIDC でも、「自分の管理下にある何か(データやアクション)」を第三者に開放する以上、同意画面はプロトコルの根幹として必須である。

OAuth認可フロー​

一番分かりやすい OAuth の説明

OAuth2.0には認証のやりとり手順(フロー)が4種類定めれており、それらはGrant Typeと呼ばれている。

OAuthが必要な理由​

第三者のアプリケーションにユーザーの ID & パスワードを渡さない

WebサービスでOAuthを使う理由​

提供するWebサービスはアカウント管理なんてやりたくない。

アカウントを発行して管理するサービス提供者側も大変です。発行したアカウントの情報が漏えいでもして、さらにそのアカウントが別サービスでも使いまわされたりしていようものならこちらも \(^o^)/オワタ な状況になることは間違いありません。 というわけで、Web サービスの利用者としてもあちこちにアカウントを作ったりしたくないし、サービス提供側としても、アカウントの管理なんか自分でやりたくないわけです。どうせ最近は誰でも Google や Facebook や Yahoo! なんかのアカウント持ってるんだから、アカウントの管理は実績のある人たちに任せてこっちは**都度「この人誰?」**って聞いて教えてもらえばいいんです。 その仕組みとして、OpenID Connectという認証プロトコルが登場しました。

OAuthにとってのGoogleやFacebook​

参考URL

OAuth2.0の用語では、Facebookは承認サーバー(AS)
認可サーバーの目的は、ユーザーを認証して認可を取得すること。
承認は通常、ユーザーに同意を求めるプロンプトによって取得されます。承認が取得されると、承認サーバーはアプリケーションにアクセス トークンを発行します。

OAuthにSNSサービスを利用する意味

ここまでは良いとしても、それでも混乱することがあります。それは、「自社のサイトにユーザーをログインさせる際、Facebook や Twitter などの外部サービスのアカウントも使えるようにしたい」、という話が出てきたときです。このとき「OAuth 認証」という言葉が出てくることが多いため、「やはりうちのサイトでも OAuth を実装しなければならないのでは?」と勘違いしてしまうことがあります。しかしこのケースでは、自社サービスは、外部サービスが実装した OAuth を利用する側ですので、自社サービス自体は OAuth を実装する必要はないのです。正確に言うと、他社の OAuth を利用するためのコード (すなわち OAuth クライアント) を書く必要はありますが、自社サービス用の OAuth サーバーを実装する必要はないのです。

OAuthがない場合​

OAuthは、第三者となるアプリケーションに対して安全にアクセス権限を提供するためのプロトコル。
たとえば、GitHubのAPIを利用するアプリケーションAをOAuthなしで使うとすると、通常はGitHubのユーザIDとパスワードをアプリケーションAに預ける必要がある。

この手法ではパスワード漏洩の危険が増しますし、アプリケーションAはGitHubに対してユーザと同じ権限を持つことになってしまう。
アプリケーションAの運営者がその気になれば、ユーザをGitHubから退会させることもできるでしょう。
OAuthを利用すると、パスワードをアプリケーションAに渡さずともよくなります。さらに、アプリケーションAがその機能を提供するのに必要な権限だけを与えることができる、

OAuth 認証フロー​

参考URL
これ実装するのにいいかもしれない

OAuth OpenID Connectの役割違い​

一般的にOAuth2は認可、OpenID Connectは認証の仕組みという形で区別される。 OAuth2は、サードパーティからの権限移譲で、Scope という概念を用いた権限の認可システムを構築するもの。
もちろんOauth2も認可の過程で認証の仕組みを用意していますが、その実態はアクセストークンと言う形でサービス提供者によって比較的バラバラの運用が取られてました。
ここに、OpenID ConnectはID Tokenという形でトークンのフォーマットや利用形態を定義したもの。

OAuth2は認可、OpenID Connectは認証の仕組みといわれるのは、技術的関心の中心がどこにあるか、を示したものに過ぎない。

OAuth2を用いたシステムにも(アクセストークンベースの)認証の仕組みはもちろんあり、OpenID Connectを用いるシステムでも、認可のシステムを実現することはもちろん可能。

OpenID Connect(認証)​

一般の方々に対してはOpenID Connectは認証の仕様であるという説明で良いと思います。一方、技術的な理解を渇望しているエンジニアの方々に対しては、OpenID Connect は ID トークン を発行するための仕様であるという割り切り方を勧めたほうが良いと考えています。というわけで、まず、ID トークンについて説明しようと思います。

OpenID ConnectはOAuth2.0に**認証の仕組みを導入するにあたって、**主に以下のような規約を定義しています。

  • Oauth2.0のAuthorization Request送信後のトークンのやり取り
  • ユーザ認証情報を表現する上でのトークンの規約
  • この2つを総称して、ID Tokenを発行するための仕組みという形で呼んでいます。

OpenID Connect(認証)で定義されるトークンのやりとり​

OpenID Connectでは、Oauth2.0のAuthorization Request送信後のトークンのやり取りt大きく3つのパターンで定めています。

  • Authorization Code Flow
  • Implicit Flow
  • Hybrid Flow

OpenID Connectを利用した認証フローがどの方式を利用しているかは、Oauth2.0のAuthorization Requestにおけるresponse_type値を確認することで判断できる。

  • response_typeの値が code -> Authorization Code Flow
  • response_typeの値が code を含まず id_token を含む -> Implicit Flow
  • その他 -> Hybrid Flow

どのフローで認証を行ったとしても、最終的にはID TokenとAccess Tokenがクライアントに返却される。

OpenID Connect利用される ID Token(JWT)​

IDトークンが分かれば OpenID Connect が分かる
OpenID ConnectとJWT の関わり - Oauth2.0 との違いなど

ID Tokenは、OpenID Connectで定義されるユーザの認証に関するトークン。
ID Tokenは、OpenID Connectで定められたそれぞれの認証フローの中でクライアントに対して返却される。

ID TokenはJWTのフォーマットで表現されるトークンです。

JWTでは、シンプルにトークンの形式のみが規程されており、payload部分のフォーマットやトークン自身の使われ方についてはほとんど言及されていなかった。

OpenID Connectで規程されるID Tokenは、JWTのpayload部に一定のフォーマットを提供するもの。
また、ID Tokenを利用した認証フローの流れなどトークンの利用方法についても細かい規定を追加しています。

OAuthとJWTの関わり​

参考URL

IDトークンはJWTの一種
参考URL

OpenID ConnectがOAuth 2.0に対しておこなった主要な拡張が、IDトークンというデータ構造。
IDトークンが JWT として表現されることも明記されている。

IDトークンの仕様では、RFC 7519で定義されているクレームのいくつかを必須のクレームとしている。
具体的には iss, sub, aud, exp, iat は必須とされている。

IDトークンでの各クレーム​

参考URL
JWTにある識別子と同名のものもあるが、少し指定内容が変わる。
IDトークンでは iss, sub, aud, exp, iat が必須とされている。

issクレーム​

issクレームは、JWTの発行者 (issuer) を識別するための識別子です。iss クレームの値は、RFC 7519 では文字列か URI (StringOrURI) とされていますが、OpenID Connect Core 1.0 のほうの定義では、より条件が多くなっており、「https:// で始まる URL (ただしクエリー部とフラグメント部は含まない)」とされています。

IDトークン発行サーバーは、他者の識別子との衝突を避けるため、issクレームの値を自分の管理下にあるドメイン名のURLとすべきです

subクレーム​

subクレームは、ユーザーの一意識別子を表す。

値の形式は、RFC 7519 では文字列か URI (StringOrURI) とされており、OpenID Connect Core 1.0 では 255 文字以内の ASCII 文字列とされています。

突然、「ユーザーの一意識別子」というものがでてきました。 これまで説明はしていませんでしたが、IDトークンはユーザーを認証した結果発行されるものなので、どのユーザーが認証されたのかの情報が含まれることになります。 その「どのユーザーが認証されたのか」という情報にあたる部分が、subクレームです。sub クレームの値は、ID トークン発行者のシステム内において、ユーザーを一意に特定することが可能な識別子です。

ルール

ユーザーの一意識別子は、一般的には、データベース内のユーザーテーブルのプライマリーキーやそれに準ずるものです。特に気にしないのであれば、プライマリーキーの値をそのまま sub の値として用いてもかまいません。気にするのであれば、何らかのロジックを用いて元々の値を変換してから sub クレームの値として用いることになります。場合によっては、ID トークンの発行を依頼したプログラムの違いによって、同じプライマリーキーから異なる sub クレーム値を生成してもかまいません

aud(Audience)​

audクレームは、当該JWTが誰を対象として発行されたのかを示すもの
別の言い方をすると、JWTの受け取り手が誰であるべきかを示している。
IDトークンの場合、このaudクレームの値は、IDトークンの発行を依頼したクライアントアプリケーションのクライアントIDとなります。

exp(expiration time)​

expクレームはJWTの有効期限を示しています。
IDトークンでは、Unixエポック (1970年1月1日(世界標準時)からの経過秒数となっています。
単位はミリ秒ではなく秒なので、IDトークンを生成もしくはパースするプログラムを書く際には注意が必要。

iat(issued at)​

iatクレームはJWTが発行された日時を示しています。
expクレームと同様、Unixエポックからの経過秒数で表現されています。

OAuth 2.0 認可コードグラント概要​

OAuth2.0には、**アクセス権の付与の方法(グラントタイプ)**が複数定義されている。
その中のひとつ、認可コードグラント(Authorization Code Grant)について説明する。
パブリッククライアント用のグラントタイプとして「PKCEを用いた認可コードグラント」も存在するが、ここでは記載しない。

OAuth2.0におけるCSRF​

OAuth2.0におけるCSRF

OAuth2.0におけるCSRFとは、被害者のクライアントアカウントに攻撃者のリソースが意図せず紐づけされる脆弱性のこと。
注意しておきたいのが、攻撃者のクライアントアカウントに被害者のリソースを紐づけられる脆弱性ではないということ。

Resource​