サイトアイコン IT & ライフハックブログ|学びと実践のためのアイデア集

OAuth 2.0とOpenID Connect(OIDC)の違い:CognitoとAuth0の設計ポイント

selective focus photo of black metal chain

Photo by Joey Kyber on Pexels.com

認証は、利用者が誰かを確かめることです。

認可は、その利用者やシステムに何を許すかを決めることです。

OAuth 2.0は主にAPIへのアクセス権を委譲するための枠組みであり、OpenID Connect(OIDC)はOAuth 2.0の上に認証の仕組みを加えます。

Amazon CognitoやAuth0は両方に対応するため、サービス名ではなく「誰を認証し、どのAPIへのアクセスを許すのか」から設計を始める必要があります。

OAuth 2.0とOIDCの違い

OAuth 2.0が扱う中心はアクセストークンです。

アクセストークンは、対象のAPIに対して許可された操作を示しますが、アプリのログイン状態を証明するためのトークンではありません。

OpenID Connect(OIDC)では、認証要求にopenidスコープを含め、認証結果を表すIDトークンを受け取ります。

IDトークンはクライアントアプリが利用し、アクセストークンは対象のAPIが利用するという分担が基本です。

OAuth 2.0とOIDCの役割の比較
比較項目 OAuth 2.0 OIDC
主な目的 APIやリソースへのアクセスを認可する 利用者を認証し、認証結果をクライアントへ伝える
中心となるトークン アクセストークン IDトークンとアクセストークン
主な受け手 リソースサーバー(API) IDトークンはクライアント、アクセストークンはAPI
代表的な用途 API呼び出し、機械間通信 ログイン、シングルサインオン、利用者情報の取得
スコープ APIごとに定義した権限 openidを起点に、必要に応じてprofileやemailを追加

アクセストークンをログイン判定に使わない理由

アクセストークンの宛先はAPIであり、クライアントアプリではありません。

形式も常にJWTとは限らないため、クライアントが中身を読み、利用者のログイン証明として扱う設計は避けます。

ログイン後のセッションを開始する際はIDトークンを使い、署名を確認するだけでなく、発行者を示すiss、対象クライアントを示すaud、有効期限のexp、要求時に送ったnonceなどを、利用するライブラリの手順に従って検証します。

IDトークンは署名されたJWTの一種であり、デコードと検証は別の処理です。

一方、APIはアクセストークンの発行者、宛先、有効期限、署名、必要なスコープを検証してから処理を許可します。

Authorization Code FlowとPKCEの流れ

利用者がログインするWebアプリ、SPA、モバイルアプリでは、Authorization Code FlowにPKCEを組み合わせる構成が基準になります。

PKCEは、認可要求を始めたクライアントだけが認可コードをトークンへ交換できるようにする仕組みです。

  1. クライアントは推測困難なcode_verifierを作り、変換したcode_challengeを認可要求に含めます。
  2. 認可サーバーは利用者を認証し、登録済みのリダイレクトURIへ認可コードを返します。
  3. クライアントは認可コードとcode_verifierをトークンエンドポイントへ送ります。
  4. 認可サーバーは対応関係を確認し、IDトークンとアクセストークンを返します。
  5. クライアントはIDトークンを検証し、APIは受け取ったアクセストークンを検証します。

OAuth 2.0の最新のセキュリティ指針であるRFC 9700は、アクセストークンがブラウザー経由の認可レスポンスに現れるImplicit Grantを新しい設計で選ばず、Authorization Code Flowを使うよう勧めています。

用途ごとのフロー選択

利用場面と選択するフロー
利用場面 基本となる選択 設計上の要点
SPAやモバイルアプリのログイン OIDCのAuthorization Code FlowとPKCE クライアントシークレットに依存せず、認可コードの横取りに備える
サーバー側で処理するWebアプリのログイン OIDCのAuthorization Code FlowとPKCE クライアント認証に加えてPKCEを使い、トークンをサーバー側で扱う
機械間通信 OAuth 2.0のClient Credentials Grant 人間の利用者を認証しないためIDトークンは使わず、API用のスコープを絞る
外部IdPを使うログイン OIDCによるフェデレーション IdPとRelying Partyの役割、発行者、クライアントID、属性対応を先に決める

リフレッシュトークンが必要な場合は、offline_accessなどサービスが定める条件を確認し、発行設定、保存場所、ローテーション、失効方法まで設計します。

Amazon Cognitoで確認すること

Amazon Cognitoのユーザープールは、アプリから見ればOIDCのIdentity Provider(IdP)として動作します。

一方、Auth0などの外部IdPをユーザープールへ登録する構成では、CognitoがRelying Partyとなり、外部IdPから受け取った情報をユーザープールの属性へ対応付けます。

この方向を曖昧にすると、発行者URL、クライアントID、コールバックURL、スコープ、属性マッピングをどちらへ設定するのか判断できません。

Cognitoが発行するIDトークンとアクセストークンはJWTですが、リフレッシュトークンはアプリが内容を解釈しない不透明な値として扱います。

外部OIDC IdPとの設定項目は、AWSのユーザープールにOIDC IdPを追加する公式手順で確認できます。

Auth0で確認すること

Auth0のIDトークンはJWTですが、アクセストークンの形式は宛先や構成によって異なるため、クライアントは不透明な値として扱います。

独自APIへ渡すアクセストークンでは、APIの識別子をaudienceとして要求し、API側で宛先とスコープを検証します。

offline_accessを指定するだけでリフレッシュトークンが必ず発行されるわけではなく、対象APIの設定や許可されたフローも一致している必要があります。

トークンごとの用途は、Auth0の公式トークン解説と、利用中のSDKの手順を基準にします。

CognitoとAuth0を連携する手順

両サービスを接続する前に、どちらが利用者を認証するIdPで、どちらが認証結果を受け取るRelying Partyなのかを一文で定義します。

たとえばAuth0を外部IdP、CognitoユーザープールをRelying Partyとする場合は、次の順に設定を照合します。

  1. Auth0側でCognito用のアプリケーションを登録し、Cognitoが指定するコールバックURLを許可します。
  2. Cognito側へAuth0の発行者URL、クライアントID、クライアントシークレット、要求するスコープを登録します。
  3. subやemailなど、実際に必要なクレームだけをCognitoのユーザー属性へ対応付けます。
  4. Cognitoのアプリクライアントで外部IdPを有効にし、アプリが受け取るCognito発行トークンの検証条件を固定します。
  5. ログイン、ログアウト、期限切れ、同意拒否、属性不足、鍵更新をテストします。

外部IdPが発行したトークンとCognitoがアプリへ発行するトークンは別物なので、発行者や宛先を取り違えないようにします。

実装前のチェックリスト

  • 認証と認可の要件を分けて記述しているか。
  • ログイン要求にopenidを含め、必要な属性に応じてスコープを絞っているか。
  • Authorization Code FlowとPKCEを使い、Implicit Grantを新規採用していないか。
  • リダイレクトURIを事前登録し、環境ごとの値を混同していないか。
  • IDトークンとアクセストークンの受け手、用途、検証条件を分けているか。
  • 署名だけでなく、iss、aud、exp、nonce、スコープを用途に応じて検証しているか。
  • トークン、認可コード、クライアントシークレットをログへ記録しない設定になっているか。
  • 鍵の更新、トークンの期限切れ、失効、ログアウトをテストしているか。

設計判断の結論

利用者のログインにはOIDCのIDトークン、APIの呼び出しにはOAuth 2.0のアクセストークンを使います。

CognitoとAuth0のどちらを選ぶ場合も、製品の設定画面から始めるのではなく、利用者、クライアント、IdP、APIの役割と信頼関係を図にしてから設定へ落とし込むと、トークンの取り違えを防ぎやすくなります。

この記事に関連する株式会社greedenの取り組み

認証基盤は、仕様を知るだけでは安全に運用できず、利用者、API、保守体制に合わせた設計が必要です。株式会社greedenは、要件定義から実装、テスト、保守まで、Webシステム開発を一気通貫で支援しています。

モバイルバージョンを終了