OAuth 2.0 / OpenID Connect 入門 - 認可と認証の違い、Authorization Code Flow + PKCE まで

OAuth 2.0 / OpenID Connect 入門 - 認可と認証の違い、Authorization Code Flow + PKCE まで

作成日:
読了:17
更新日:

「Google でログイン」や外部 API 連携で必ず出てくる OAuth 2.0OpenID Connect(OIDC)。なんとなく使ってはいても、「OAuth は認証じゃないの?」「access token と ID token は何が違う?」「Implicit Flow はもう使っちゃダメ?」あたりは曖昧になりがちです。

この記事では、Web アプリ開発者向けに、OAuth と OIDC の違い・登場人物・トークンの役割・推奨フローを、RFC 6749 / 7636 / 6750 / 9700OpenID Connect Core 1.0、そして OAuth 2.1 ドラフトを一次ソースに整理します。

OAuth(認可)と OIDC(認証)は何が違うか

まず最重要の区別です。

  • OAuth 2.0 は「認可(authorization)」の仕組みです。「このアプリにあなたのカレンダーを読む権限を与えてよいか」を扱います。RFC 6749 の冒頭でも、third-party application に対して HTTP サービスへの限定的なアクセス権を与える枠組みだと定義されています。
  • OpenID Connect は「認証(authentication)」の仕組みです。「ログインしているのは誰か」を扱います。OIDC Core 1.0 はこれを「OAuth 2.0 プロトコルの上に乗る、シンプルな identity layer」と定義しています。

つまり OAuth 単体は「誰がログインしているか」を保証する規格ではありません。ユーザー認証(サインイン)をやりたいなら、OAuth の上に OIDC を重ねるのが正しい設計です。「OAuth でログイン」と言われるものの多くは、実態としては OIDC を使っています。

NOTE

「OAuth = ログイン」という説明は不正確です。OAuth はアクセス権の委譲(認可)であって、本人確認(認証)はそのままでは扱いません。認証を標準的にやるための層が OIDC です。

登場人物(役割)

OAuth のフローは、次の役割の登場人物のやり取りとして理解すると整理しやすいです(RFC 6749 の用語)。

役割英語説明
リソースオーナーResource Owner保護されたリソースの持ち主。多くの場合エンドユーザー本人
クライアントClientリソースにアクセスしたいアプリ(あなたが作る Web/モバイルアプリ)
認可サーバーAuthorization Serverユーザーを認証し、同意を得てトークンを発行するサーバー
リソースサーバーResource Serverアクセストークンを受け取り、保護されたリソース(API)を提供するサーバー

クライアントには2種類あります。RFC 6749 はこれを機密クライアント(confidential client)公開クライアント(public client)に分類します。

  • 機密クライアント: クライアントシークレットを安全に保持できる。サーバーサイドの Web アプリなど。
  • 公開クライアント: シークレットを秘密にできない。SPA(ブラウザ内 JS)やネイティブアプリなど。

この区別が、後述する PKCE がなぜ重要かに直結します。

Authorization Code Flow + PKCE の流れ

現在もっとも推奨される基本フローが Authorization Code Flow(認可コードフロー)に PKCE を組み合わせたものです。PKCE(Proof Key for Code Exchange、「ピクシー」と読む)は RFC 7636 で定義されています。

考え方はこうです。

  1. クライアントは毎回ランダムな code_verifier を生成し、そのハッシュ(code_challenge)を認可リクエストに付ける。
  2. 後でトークンと引き換える際に、元の code_verifier を提示する。
  3. 認可サーバーはハッシュが一致するか検証する。

これにより、たとえ認可コードが途中で盗まれても、code_verifier を知らない攻撃者はトークンを取得できません。

Loading diagram...

認可リクエストの URL はおおよそ次のようになります。ブラウザでこの URL へリダイレクトします。

認可リクエスト(ブラウザのリダイレクト)
GET /authorize?response_type=code
  &client_id=s6BhdRkqt3
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
  &scope=openid%20profile%20email
  &state=af0ifjsldkj
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256 HTTP/1.1
Host: auth.example.com

ユーザーがログイン・同意すると、認可サーバーは redirect_uri に認可コードを付けて返します。クライアントはそのコードをトークンエンドポイントに POST して、トークンと交換します。

トークンリクエスト(認可コード -> トークン)
curl -X POST https://auth.example.com/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d code=SplxlOBeZQQYbYS6WxSbIA \
  -d redirect_uri=https://app.example.com/callback \
  -d client_id=s6BhdRkqt3 \
  -d code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

ポイントは、access token がブラウザのアドレスバー(URL)に乗らないことです。コードだけがリダイレクトで返り、トークンはサーバー間(または XHR)の安全な経路で受け取れます。これが後述の Implicit Flow との決定的な違いです。

各種トークンの役割

OAuth/OIDC で出てくるトークンは役割が違います。混同しないことが大事です。

トークン規格役割形式渡す相手
access tokenOAuth 2.0API へのアクセス権を表す。「何ができるか」不透明文字列 or JWTリソースサーバー(API)
refresh tokenOAuth 2.0access token を再発行するための長命トークン不透明文字列認可サーバーのみ
ID tokenOpenID Connect認証結果。「誰がいつログインしたか」JWTクライアント自身

重要な注意点をいくつか。

  • access token はクライアントが中身を解釈してはいけません。クライアントにとっては「リソースサーバーへ渡すための不透明な文字列」です。形式が JWT でも、それはリソースサーバー側の都合です。
  • アクセストークンの使い方は RFC 6750(Bearer Token)が定めており、Authorization: Bearer <token> ヘッダで送るのが基本です。
  • ID token は逆にクライアントが検証して読むためのものです。OIDC Core 1.0 が「ID Token は JWT として表現される」と定義しており、sub(ユーザー識別子)や iss/aud/exp、認証時刻 auth_time などのクレームを含みます。
  • ユーザーのプロフィール詳細が欲しいときは、ID token に頼りきらず UserInfo エンドポイントに access token を提示して取得します。

JWT の構造や検証の詳細は JWT(JSON Web Token)の仕組みと正しい使い方 を参照してください。ID token はまさに JWT なので、iss/aud/exp の検証や alg 許可リストの話がそのまま当てはまります。

他のフローと使い分け(と非推奨フロー)

OAuth にはいくつかのフロー(grant type)があります。用途で使い分けますが、歴史的に使われていたが今は非推奨のものもあります。

フロー用途現在の扱い
Authorization Code + PKCEWeb/SPA/モバイルでのユーザー認可推奨(既定)
Client Credentialsユーザー不在のサーバー間連携(マシン間)適切な用途では推奨
Device Authorization(Device Code)入力が貧弱な端末(TV など)該当用途で利用可
Implicit Flowかつての SPA 向け非推奨
Resource Owner Password Credentials(ROPC)アプリにパスワードを直接渡す非推奨/廃止方向

なぜ Implicit Flow は非推奨になったのか

Implicit Flow は、トークンエンドポイントを介さずaccess token を直接リダイレクト(URL フラグメント)で返すフローでした。SPA がまだ CORS で安全にトークン交換しづらかった時代の妥協策です。

これが危険なのは、access token がブラウザの履歴・Referer・ログなどに残りやすく、漏洩しやすいからです。OAuth のセキュリティベストプラクティスである RFC 9700(Best Current Practice for OAuth 2.0 Security、BCP 240、2025年公開)は、Implicit のようなaccess token をリダイレクトで返す方式を使うべきでないとしています。今の SPA は Authorization Code + PKCE を使うべきです。

なぜ ROPC は非推奨なのか

ROPC は、ユーザーが自分の ID とパスワードをクライアントアプリに直接入力し、アプリがそれを認可サーバーに送ってトークンをもらう方式です。これは OAuth が本来避けたかった「アプリにパスワードを預ける」状態そのもので、フィッシングや MFA との相性の悪さもあり、推奨されません。

WARNING

Implicit Flow と ROPC は、OAuth 2.1 ドラフト(後述)では明確に除外(omit)される方向で記述されています。新規実装では使わず、Authorization Code + PKCE か、用途に応じて Client Credentials / Device Code を選んでください。

OAuth 2.1 のステータス(ドラフトであることに注意)

「これからは OAuth 2.1」という話をよく聞きますが、正確に押さえておきたい点があります。

OAuth 2.1 は2026年6月時点で正式な RFC ではなく、IETF のドラフト(Internet-Draft)です。具体的には draft-ietf-oauth-v2-1(執筆時点で -15、2026年3月公開、Standards Track を意図、期限切れは2026年9月予定)という状態です。正式仕様として確定しているわけではないので、「OAuth 2.1 では〜と決まっている」とは断言できません。

ただし方向性は明確で、OAuth 2.1 ドラフトは RFC 6749 と RFC 6750 を統合・整理し、過去10年のベストプラクティスを取り込むものです。具体的には次を標準化しようとしています。

  • PKCE を必須化(公開クライアントだけでなく、認可コードフロー全般で)
  • redirect_uri の完全一致(exact matching)を必須化
  • Implicit Grant と ROPC を除外(廃止方向)

つまり、「OAuth 2.1 ドラフトと RFC 9700 が示す現在のベストプラクティス」を実務の指針にするのが妥当です。PKCE はもはや公開クライアント限定の追加策ではなく、機密クライアントを含めて推奨される、という点は覚えておいてください。

実装時の注意

最後に、実装でつまずきやすい・事故りやすいポイントです。

state で CSRF を防ぐ

認可リクエストに推測不能な state パラメータを付け、コールバックで一致を検証します。これを省くと、攻撃者の認可コードを被害者のセッションに紐付ける CSRF が成立し得ます。CSRF 全般の考え方は Cookie / セッション / SameSite ガイド も参考になります。

PKCE は常に使う

公開クライアントでは必須、機密クライアントでも推奨です。code_challenge_methodS256(SHA-256)を使い、plain は避けます。

redirect_uri は完全一致で検証する

認可サーバー側で、登録済みの redirect_uri完全一致(前方一致やワイルドカードではなく)で照合します。緩い検証はオープンリダイレクトやコード横取りの入口になります。

トークンの保管場所に注意する

access token / refresh token をどこに置くかは難所です。localStorage は XSS で盗まれます。httpOnly Cookie は XSS に強い一方で CSRF 対策(SameSite など)が要ります。万能解はないので、XSS を塞ぐ前提で用途に応じて選びます。ここは JWT の保管と同じ論点なので JWT の記事 の保存場所の節も合わせて読んでください。

スコープは最小限に

scope で要求する権限は、本当に必要なものだけに絞ります。過剰なスコープ要求は、漏洩時の被害も同意のハードルも上げます。

NOTE

認証方式そのものをより安全にしたいなら、パスワードに依存しない パスキー / WebAuthn との組み合わせも検討の価値があります。OIDC の認可サーバー側でパスキーを使う、といった構成が現実的です。

まとめ

  • OAuth 2.0 は認可(アクセス権の委譲)、OIDC は認証(誰がログインしたか)。OIDC は OAuth の上に乗る identity layer
  • 登場人物はリソースオーナー / クライアント / 認可サーバー / リソースサーバー。クライアントは機密と公開に分かれる
  • 推奨は Authorization Code Flow + PKCE。access token を URL に乗せず、コードを安全にトークンと交換する
  • トークンは役割が別。access token は API 用(クライアントは中身を見ない)、refresh token は再発行用、ID token は認証結果の JWT
  • Implicit Flow と ROPC は非推奨。RFC 9700(BCP 240、2025年)と OAuth 2.1 ドラフトがその方針を示す
  • OAuth 2.1 は2026年6月時点でまだ IETF ドラフト(正式 RFC ではない)。ただし PKCE 必須・redirect_uri 完全一致・Implicit/ROPC 除外という方向は明確
  • 実装では state / PKCE(S256) / redirect_uri 完全一致 / トークン保管 / 最小スコープを押さえる

OAuth と OIDC は登場人物とトークンの役割を一度整理すれば、見通しがぐっと良くなります。新規実装は迷わず Authorization Code Flow + PKCE から始めてください。

参考リンク

Cookie・セッション・SameSite の基礎 - Secure / HttpOnly と CSRF・CORS の関係

Cookie・セッション・SameSite の基礎 - Secure / HttpOnly と CSRF・CORS の関係

11

Web認証の土台となる Cookie・セッション・SameSite を実務目線で整理します。Set-Cookie の属性(Expires/Max-Age・Domain/Path)、Secure と HttpOnly が防ぐ脅威、SameSite の Strict/Lax/None の違いと None に Secure が要る理由、サーバー側セッションとログイン後の ID 再生成、SameSite だけで CSRF を防ぎきれない理由、クロスオリジンで Cookie を送る CORS の条件、__Host-/__Secure- プレフィックスまで、MDN・RFC 6265bis・OWASP を一次ソースにまとめます。

JWT(JSON Web Token)の仕組みと正しい使い方 - 署名・検証とセキュリティの落とし穴

JWT(JSON Web Token)の仕組みと正しい使い方 - 署名・検証とセキュリティの落とし穴

12

JWT(JSON Web Token)を実務目線で整理します。header.payload.signature の3部構造と Base64URL、iss/sub/aud/exp などのクレーム、HS256 と RS256/ES256 の使い分け、検証の流れ、そして alg:none 攻撃・アルゴリズム混同・「JWT は暗号化ではないので中身は誰でも読める」という誤解・失効の難しさといった落とし穴まで、RFC 7519/7515/7518/8725 と OWASP を一次ソースにまとめます。

Passkeys / WebAuthn 入門 - パスワードレス認証を管理画面に入れる前に知っておくこと

Passkeys / WebAuthn 入門 - パスワードレス認証を管理画面に入れる前に知っておくこと

7

パスキー(Passkeys)と Web Authentication API(WebAuthn)の仕組みを、公開鍵暗号・登録/認証セレモニー・フィッシング耐性の観点から整理します。なぜパスワードより安全なのか、管理画面に導入するときの判断材料(復旧手段・MFAとの違い)まで、実装目線でまとめます。