OIDC / OAuth 2.0 の用語を 3 つの軸で整理する — Authorization Code / Implicit / Confidential / Public / PKCE
OIDC と OAuth 2.0 の用語は、対立しているように見えて実は別の軸のものが多い。「Implicit の反対は Confidential だっけ?」のような混乱は、ここから来る。自分も自作の OIDC プロバイダーを作っているときに、頭の中がしばらく整理できていなかった。
軸を 3 本に分けて覚えると、ほぼ解消する。
| 軸 | 対立する用語 | 何を決めるか |
|---|---|---|
| 1. フロー | Authorization Code ↔ Implicit ↔ Hybrid | トークンをどこで受け取るか |
| 2. クライアント種別 | Confidential ↔ Public | クレデンシャルを秘密に保てるか |
| 3. クライアント認証方式 | client_secret_basic / private_key_jwt / tls_client_auth / none | token endpoint でどう本人証明するか |
PKCE はこの 3 軸すべてと直交している。軸ではなく、軸をまたいで効く保護機構だ。
つまり Implicit の対義語は Authorization Code で、Confidential の対義語は Public。この 2 つは別の軸なので、直接対立しない。
軸 1: フロー — トークンをどこで受け取るか
response_type で決まる。
| response_type | 受け取り方 | 現状 |
|---|---|---|
code |
引換券 (code) だけをリダイレクトで受け取り、バックチャネルで token endpoint に交換 | PKCE と併せてこれ一択 |
id_token / id_token token (Implicit) |
トークンがフロントチャネル (URL fragment) に直接返る | 非推奨 |
code id_token 等 (Hybrid) |
両方 | 非推奨方向 |
[Authorization Code Flow]
ブラウザ ──① 認可リクエスト──▶ 認可サーバー
◀─② code (リダイレクト)──
アプリ ─────③ code + PKCE verifier ──▶ token endpoint ← バックチャネル
◀────④ id_token / access_token ──
code は引換券であって、それ自体には何の情報も入っていない。中身は ④ で初めて手に入る。フロントチャネル (ブラウザ) をトークンが通らないのが要点だ。
Implicit がなぜ退場したか
トークンが URL fragment に載るため、ブラウザの履歴、Referer ヘッダ、リバースプロキシや CDN のアクセスログ、拡張機能や同一ページ上の他のスクリプト、これらすべてが漏洩経路になる。
さらに、フロントチャネルで返るトークンは発行相手を暗号的に紐付けられないため、攻撃者が横取りしたトークンを自分のセッションに注入する攻撃 (token injection) を防ぎにくい。
RFC 9700 (OAuth 2.0 Security Best Current Practice, 2025-01) が非推奨とし、OAuth 2.1 では削除された。
厳密には、RFC 9700 が名指しで否定しているのは response_type=token (access_token をフロントチャネルに出すもの) だ。response_type=id_token のみ + response_mode=form_post の構成は、id_token が API の bearer credential ではないぶん危険度が低く、古い構成では今も見かける。それでも新規に選ぶ理由はない。
軸 2: クライアント種別 — Confidential / Public
判定基準は RFC 6749 §2.1 にある。クレデンシャルの機密性を維持できるか、それだけだ。
| 例 | client_secret | |
|---|---|---|
| Confidential | サーバサイド Web アプリ、バッチ、サーバ間連携 | 持てる。サーバ内に置ける |
| Public | SPA、モバイルアプリ、デスクトップアプリ、CLI | 持てない。配布物に埋めても逆アセンブルや DevTools で読まれる |
「Public client は secret を持たないから危険」ではない。持てないという事実を正しく認めた上で設計されているのが public client であって、危険なのは「public client なのに secret を埋め込んで confidential のつもりでいる」構成のほうだ。
軸 3: クライアント認証方式
Confidential client が token endpoint で自分を証明する方法で、token_endpoint_auth_method として登録する。
| 方式 | 内容 |
|---|---|
client_secret_basic |
secret を Authorization ヘッダで送る。最も一般的 |
client_secret_post |
secret をリクエストボディで送る |
private_key_jwt |
クライアントが秘密鍵で署名した JWT (client assertion) を送る。secret が線に乗らない |
tls_client_auth |
mTLS のクライアント証明書で認証 |
none |
public client。クライアント認証をしない |
private_key_jwt と tls_client_auth は、共有秘密をネットワークに流さないという点で client_secret_* より強い。金融系など高セキュリティ要件で要求される。
PKCE が座標系を変えた
昔はこういう連鎖で考えられていた。
SPA は public client → client_secret が無い → token endpoint でクライアント認証できない → code を交換できない → だから Implicit を使うしかない
この「Public だから Implicit」という誤った結びつきが、Implicit と Confidential を対立概念だと錯覚させる原因になっている。
PKCE (RFC 7636) がこの前提を壊した。
PKCE はリクエストごとに使い捨ての code_verifier を生成し、認可リクエストにはそのハッシュ (code_challenge) だけを送る。code を横取りしても、元の code_verifier を知らなければトークンに交換できない。
秘密の共有も鍵管理も発生しない (毎回使い捨て)。したがって client_secret が無い public client でも Authorization Code Flow が使える。
結果、現在の対応はこうなる。
| Authorization Code + PKCE | Implicit | |
|---|---|---|
| Confidential client | 推奨 | 使わない |
| Public client | 推奨 | 使わない |
「Public だから Implicit」はもう成立しない。
また PKCE は public client 限定の対策ではない。RFC 9700 は全クライアントに推奨し、OAuth 2.1 では必須とされている。confidential client でも、認可レスポンスの横取り経路は塞いでおく価値がある。
おまけ: 「JWT か authorization code か」も対立ではない
同じ種類の混同として多いのがこれだ。
id_token は必ず JWT で、OIDC Core が "The ID Token is represented as a JSON Web Token (JWT)" と定義している。例外はない。authorization code は、その JWT を安全に受け取るための手段だ。つまり二択ではなく両方を使う。code を交換した結果として JWT が返る。
一方で access_token のフォーマットは仕様上自由で、ここは本当に分岐がある。
| 検証方法 | 特徴 | |
|---|---|---|
| JWT (RFC 9068) | ローカルで署名検証 | 速い。認可サーバーへの往復が不要。失効が効かない (期限まで有効) |
| opaque (ただの乱数文字列) | Token Introspection (RFC 7662) で問い合わせ | 即座に失効できる。毎回往復が発生する |
「アクセストークンを JWT にすべきか」という議論はこちらの話であって、id_token には選択の余地がない。
ちなみに UserInfo エンドポイントのレスポンスは通常ただの JSON だ (署名や暗号化をしたい場合は JWT にもできる)。「OIDC は全部 JWT」というわけでもない。
参考
- RFC 6749 §2.1 — Client Types (Confidential / Public)
- RFC 7636 — PKCE
- RFC 7662 — OAuth 2.0 Token Introspection
- RFC 9068 — JWT Profile for OAuth 2.0 Access Tokens
- RFC 9700 — OAuth 2.0 Security Best Current Practice
- OpenID Connect Core 1.0 §3 (Authentication) / §2 (ID Token)
開発相談をお待ちしています。