OAuth 2.0 / OIDC のフロー全比較 — どれを使うか判断フローチャート付き

Authorization Code、PKCE、Client Credentials、Device Authorization、Implicit、Resource Owner Password の6つのフローを比較。判断フローチャートと PKCE の仕組みをわかりやすく解説。

はじめに

OAuth 2.0 / OIDC には複数の認証フローがあり、「どれを使えばいいのか」が最初の壁になります。この記事では、各フローの動き・用途・セキュリティ特性を整理し、判断フローチャートで選び方を示します。

フロー一覧

フロー一言で使う場面ステータス
Authorization Code一番安全、基本これサーバーサイドのある Web アプリ推奨
Authorization Code + PKCE↑の Public クライアント版SPA、モバイル、CLI推奨
Client Credentialsユーザー不在、マシン間通信バックエンド同士の API 呼び出し推奨
Device Authorization画面入力できないデバイステレビ、CLI、IoT推奨
Implicitトークン直接返却昔の SPA非推奨
Resource Owner Passwordパスワード直送レガシー移行の一時しのぎ非推奨

各フローの動き

Authorization Code

サーバーサイドのある Web アプリ向け。最も一般的で最も安全。

ブラウザ
  │ 1. ログインボタン押下

OIDC Provider (auth.example.com)
  │ 2. ログイン画面 → 認証
  │ 3. 認可コード発行

ブラウザ (redirect_uri に戻る)
  │ 4. 認可コードをバックエンドに渡す

バックエンド
  │ 5. 認可コード + client_secret → トークン交換(サーバー間通信)
  │ 6. トークン取得

セッション確立

Authorization Code + PKCE

SPA やモバイルアプリなど、client_secret を安全に保持できないクライアント向け。

ブラウザ / モバイル
  │ 1. code_verifier(ランダム値)を生成
  │    code_challenge = SHA256(code_verifier)
  │ 2. 認可リクエスト(code_challenge 付き)

OIDC Provider
  │ 3. code_challenge を保存、認可コード発行

ブラウザ / モバイル
  │ 4. トークン交換(code_verifier 付き)

OIDC Provider
  │ 5. SHA256(code_verifier) == 保存した code_challenge ?
  │    → 一致すればトークン発行

トークン取得

client_secret の代わりに PKCE で「認可コードを要求した人 = トークン交換する人」を証明します。

Client Credentials

ユーザーが介在しない、サービス間通信向け。

バックエンド A
  │ 1. client_id + client_secret で直接トークン要求

OIDC Provider
  │ 2. トークン発行(sub はサービス自体)

バックエンド A
  │ 3. トークンを使ってバックエンド B の API を呼ぶ

バックエンド B
POST /oidc/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=batch-service
&client_secret=xxx
&scope=api:internal

Device Authorization

キーボード入力が困難なデバイス向け。

デバイス(テレビ等)
  │ 1. POST /device/code → ユーザーコード取得

  │ 画面表示:
  │ 「https://auth.example.com/device にアクセスして
  │  コード ABCD-1234 を入力してください」

  │                   ユーザー(スマホのブラウザで操作)
  │                     │ 2. URL にアクセス
  │                     │ 3. コード入力
  │                     │ 4. ログイン → 承認
  │                     ▼
  │                   OIDC Provider: 承認を記録

  │ 5. デバイスがポーリング(数秒間隔)
  │    POST /token { grant_type=device_code, device_code=xxx }
  │    → "authorization_pending" → "authorization_pending" → トークン発行!

トークン取得

Implicit(非推奨)

ブラウザ
  │ 1. 認可リクエスト(response_type=token)

OIDC Provider
  │ 2. トークンが URL フラグメントで直接返る

https://app.com/callback#access_token=xxx&token_type=Bearer

Resource Owner Password(非推奨)

ユーザー → アプリにパスワードを直接入力


          アプリが OIDC Provider にパスワードを送信
          POST /token { grant_type=password, username=..., password=... }

PKCE の仕組み

PKCE(Proof Key for Code Exchange、ピクシーと読む)は、認可コードの横取り攻撃を防ぐ仕組みです。

何を防ぐか

正規アプリ → OIDC Provider → 認可コード発行

                    悪意あるアプリが認可コードを横取り


                    横取りしたコードでトークン交換 → 成功してしまう!

特にモバイルアプリのカスタムスキーム(myapp://callback)は、別アプリが同じスキームを登録して横取りできます。

PKCE がこれを防ぐ

1. クライアントがランダム値を生成
   code_verifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"

2. そのハッシュを計算
   code_challenge = BASE64URL(SHA256(code_verifier))
   → "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"

3. 認可リクエストに code_challenge を付ける
   GET /authorize?...&code_challenge=E9Melh...&code_challenge_method=S256

4. OIDC Provider は code_challenge を保存

5. トークン交換時に code_verifier(元の値)を送る
   POST /token  code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

6. OIDC Provider が検証:
   SHA256("dBjftJeZ4CVP...") == "E9Melhoa2Owv..." → 一致!→ トークン発行

ハッシュの一方向性により:

誰が使うべきか

クライアント種別PKCEclient_secret推奨
SPA必須持てないPKCE のみ
モバイル必須持てないPKCE のみ
CLI必須持てないPKCE のみ
SSR Web アプリ推奨使える両方(ベスト)

OAuth 2.1 では Confidential Client でも PKCE が必須になる予定です。今から両対応にしておくのが無難。

判断フローチャート

ユーザーはいる?

  ├─ No → Client Credentials

  └─ Yes

      画面でログインできる?

        ├─ No → Device Authorization

        └─ Yes

            バックエンドはある?

              ├─ Yes → Authorization Code + PKCE
              │        (client_secret も使えるなら両方)

              └─ No(SPA / モバイル)

                  → Authorization Code + PKCE(必須)

迷ったら Authorization Code + PKCE が正解です。

セキュリティ比較

フロートークン露出リスクclient_secret 要否PKCE推奨度
Authorization Code低(バックチャネル)必須推奨
Authorization Code + PKCE不要必須
Client Credentials低(サーバー間)必須不要
Device Authorization任意不要
Implicit高(URL に露出)不要不要
Resource Owner Password高(パスワード露出)任意不要

まとめ

← Back to all posts