OAuth 2.0 / OpenID Connect 入門
認証・認可に初めて触れる方には、関連する規格が略語の羅列に見えるかもしれません。OAuth、OIDC、JWT、OP、RP、RS、PAR、JAR、JARM、DPoP、mTLS、PKCE、FAPI…。ただ、押さえるべき 役割は 3 つだけ で、ほとんどの規格はこの 3 者の間の同じ処理を少しずつ強化したものです。
略号の早見表(まずここを開いてください)
3 つの役割
- OP(OpenID Provider) — ユーザを認証してトークンを発行するサーバ。
go-oidc-providerはここに該当します。純粋 OAuth 文脈では AS(Authorization Server)とも呼ばれます。 - RP(Relying Party) — OP を使ってユーザをログインさせるクライアントアプリ。OAuth の文脈では client とも呼ばれます。
- RS(Resource Server) — アクセストークンを受け取ってデータを返す API。
トークンと暗号
- JWT(JSON Web Token、RFC 7519) —
header.payload.signatureを.でつないだ base64url 文字列。中身を読め、署名も検証できます。 - JWS(JSON Web Signature、RFC 7515) — JWT が使う署名方式。
- JWE(JSON Web Encryption、RFC 7516) — 暗号化版。外側の入れ物が内側の JWS を包みます。
- JWK / JWKS(RFC 7517) — JSON Web Key / Key Set。OP の公開鍵集合で
/jwksから取得します。詳しくは JOSE 基礎 を参照してください。 - PKCE(RFC 7636) — 認可コードに対する所持証明。認可コードを横取りされてもトークンに交換されないようにします。発音は「ピクシー」。
プロファイル / 強化の略号
- PAR(RFC 9126) — Pushed Authorization Request。RP がまず authorize 要求を OP に POST し、ブラウザは
request_uri参照だけを運びます。 - JAR(RFC 9101) — JWT-Secured Authorization Request。authorize 要求自体を署名 JWT にします。
- JARM(OpenID FAPI) — JWT-Secured Authorization Response Mode。authorize 応答 を署名 JWT にします。
- DPoP(RFC 9449) — Demonstrating Proof of Possession。クライアントが保持する鍵にトークンをリクエストごとに結びつけます。
- mTLS(RFC 8705) — mutual TLS。考え方は DPoP と同じで、結びつける先がクライアントの TLS 証明書になります。
- FAPI(Financial-grade API) — 上記をまとめて固定する OpenID プロファイル。
- CIBA — Client-Initiated Backchannel Authentication。ブラウザを持たないデバイスから、ユーザのスマートフォンなどへ認証要求を送るバックチャネル認証。
早めに出てくる claim
sub— Subject。当該 OP におけるユーザの不透明な識別子。aud— Audience。トークンの宛先。iss— Issuer。トークンに署名した OP。scope— 半角スペース区切りの権限リスト(openid profile emailなど)。acr(Authentication Context Class Reference) — 認証手段が提供した保証水準。step-up で使われます。amr(Authentication Methods References) — 実際に使った認証要素を表す RFC 8176 の値(pwd、otp、mfa、hwk、face、fpt)。cnf— confirmation。トークンが結びついている鍵(DPoP のjktthumbprint または mTLS のx5t#S256)。
このページで触れる仕様
- RFC 6749 — OAuth 2.0 Authorization Framework
- RFC 6750 — Bearer Token Usage
- RFC 7519 — JSON Web Token (JWT)
- RFC 7636 — PKCE
- RFC 7662 — Token Introspection
- RFC 9068 — JWT Profile for OAuth 2.0 Access Tokens
- OpenID Connect Core 1.0
- OpenID Connect RP-Initiated Logout 1.0
- FAPI 2.0 Security Profile
3 つの役割
上の図は「誰が何を担当しているか」を示しています。ログインの実際のステップ(/auth への redirect、認可コードの交換、トークンの取得)は、後段の 認可コード + PKCE で説明します。
1 つのプログラムが 2 つの役割を持つこともある
たとえば Backend for Frontend は、ユーザをログインさせる RP であると同時に、SPA からアクセストークン付きで呼ばれる API を持つ RS でもあります。
OAuth 2.0 と OpenID Connect の違い
OAuth 2.0 は 認可の委譲 を担う規格です。「Alice のアプリが、サービス X 上の Alice のデータを読む許可をもらう」ための仕組みで、アプリに Alice が誰なのか は伝えません。アクセストークンは認可を表すだけで、opaque にするか JWT などの自己完結型にするかは認可サーバが決めます。
OpenID Connect(OIDC)は OAuth 2.0 + 認証結果 を扱う規格です。OP はアクセストークンに加えて ID トークン(署名付き JWT)を発行し、「このトークンはユーザ sub=alice123 向けに、audience client_id=myapp で、この時刻に発行された。Alice について次の claim は真である」と表明します。
OIDC はさらに、/userinfo エンドポイント、discovery 文書、RP-Initiated Logout、Back-Channel Logout 通知を追加します。
JWT とは
署名付き compact JWT(JSON Web Token、RFC 7519)は、3 つの base64url エンコード部分を . で繋いだ文字列です(header.payload.signature)。header と payload は JSON で、signature は受け手が公開鍵で発行者を暗号学的に検証するための部分です。暗号化された JWT は 5 つの部分を持つ compact JWE で、署名済み JWT をその中に包むこともできます。
OIDC では ID トークンは常に JWT です。本ライブラリのアクセストークンも既定では JWT で、必要なら opaque 形式に切り替えられます。JSON を読めて署名を検証できれば、既定の形式は読めます。
Opaque と JWT の違い
- Opaque token: 受け手にとっては意味のないランダム文字列。何を許可するかを知るには、発行元の introspection エンドポイント(RFC 7662)に問い合わせてトークンを引いてもらいます。
- JWT: 中身がトークンにエンコードされていて、署名を検証するだけで(オフラインで)受け手が中身を信用できます。
判断軸は次のとおりです。opaque token は確認のたびに OP へ問い合わせが必要ですが、すぐに失効させられます。JWT は手元で検証できますが、受け手が失効も確認しない限り、期限が切れるまで有効なままです。本ライブラリがこの両者をどう折衷しているかは ID トークン / アクセストークン / userinfo を参照してください。
どちらを使えばいい?
- 純粋な OAuth 2.0: 「このトークンは
POST /thingsを呼べる」だけが言えれば良い API。サービス間通信でよく使われます。 - OIDC: 人間がログインして、アプリが「こんにちは Alice」と言いたいケース。Web・モバイルのログインはほぼすべて OIDC です。
go-oidc-provider は既定で OIDC(openid scope 必須)として動作し、op.WithOpenIDScopeOptional() で純粋 OAuth 2.0 にも切り替えられます。
出てくる 4 種類のトークン
| トークン | 寿命 | 何のためのもの | 行き先 |
|---|---|---|---|
| 認可コード | 数十秒(既定 60 秒) | 1 回限りの不透明な文字列。 | サーバ間通信: RP → OP /token。 |
| アクセストークン | 数分(既定 5 分) | API を呼ぶときの Authorization: Bearer … に乗せる。JWT または opaque。 | RP → RS。 |
| リフレッシュトークン | 数日〜数週間(既定 30 日) | 長寿命。再認証なしに新しいアクセストークンを取得するために使う。 | RP → OP /token。 |
| ID トークン | 数分(既定 10 分) | ユーザが誰かを証明する署名付き JWT。API には送らない。 | OP → RP、RP 内で消費。 |
ID トークンを Bearer に乗せない
よくある落とし穴です。ID トークンの audience は RP であって RS ではありません。API に Authorization: Bearer で送ると通ってしまうことがありますが、誤りです。RP 向けの claim(email など)を、ユーザが触れるすべての API にさらすことになります。
API には、アクセストークンを使ってください。 RFC 7662 の introspection、または RFC 9068 の self-contained JWT として検証します。
# NG: OP が RP に発行した ID トークンを API に渡している
GET /orders HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJ...id_token...
# OK: API audience のアクセストークンを渡す
GET /orders HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJ...access_token...最もよく見かける処理: 認可コード + PKCE
/token より前はすべてブラウザを経由します。state と code_challenge をこれほど早い段階で送るのはそのためで、戻ってきたリダイレクトを送り出したリクエストに結び付けられるのはこの 2 つだけです。トークン要求はブラウザのレーンを飛び越える、ブラウザには見えない直接のバックチャネル通信です。PKCE の部分(/auth への redirect に付く code_challenge と、POST /token で送る code_verifier)は、悪意あるアプリが横取りした認可コードを使えないようにする仕組みです。op.WithProfile を指定しない OP は、すべての認可リクエストで PKCE を要求します(profile.OAuth21)。profile.OIDCCore を指定すると、confidential client では任意になります。詳しくは 認可コードフロー + PKCE を参照してください。
このサイトでよく出てくる用語
| 用語 | 意味 |
|---|---|
| scope | 半角スペース区切りの権限リスト(例: openid profile email)。ユーザがこれに同意します。 |
| claim | トークン内のフィールド(sub、email、email_verified など)。 |
| 同意 | 「このアプリはあなたのメールアドレスを受け取りたいと言っています」とユーザに確認する画面、またはその結果。OP が記録し、同じ scope の次回ログインでは画面を省略します。 |
audience(aud) | トークンの宛先。ID トークンは aud = client_id、アクセストークンは aud = resource server です。 |
issuer(iss) | トークンに署名した OP。RP も RS も、自分が期待する値と一致するか確認します。 |
| JWKS | JSON Web Key Set。OP の公開鍵集合で、/jwks から取得します。RP は ID トークンの検証に使います。 |
| Discovery 文書 | /.well-known/openid-configuration。OP のエンドポイント、scope、アルゴリズム、機能をまとめた JSON のカタログ。 |
acr と amr を 1 段落で
acr は認証が どれだけ強かったか(aal2 のような保証水準ラベル)を表し、amr は どの認証要素を使ったか(["pwd","otp"] のような配列)を表します。RP が機微な操作のために高い保証を必要とするときは、acr_values で高い acr を要求します。OP は step-up 認証を実行し、新しい ID トークンを発行します。RFC 8176(Authentication Method Reference Values)が標準 amr 値を規定し、RFC 9470(OAuth 2.0 Step Up Authentication Challenge Protocol)が WWW-Authenticate: error="insufficient_user_authentication" 経由の step-up を標準化しています。設定方法は MFA / ステップアップ を参照してください。
FAPI 2.0 が追加するもの
金融グレード・医療グレードの OP には、OIDC の上に FAPI 2.0 Security Profile の要求を重ねる必要があります。送信者制約付きトークン(DPoP / mTLS)、PAR(認可要求を先にサーバ間で送る)、より絞られた alg 許可リストです。このプロファイルは JAR(認可要求への署名)を必須にしていませんが、本ライブラリの FAPI2Baseline 設定では JAR も有効になります。次の 1 行で、この設定を有効化できます。
op.WithProfile(profile.FAPI2Baseline)略号を一通り解説した入門は FAPI 2.0 入門 にあります。DPoP / mTLS の仕組みは 送信者制約 を、全体構成は ユースケース: FAPI 2.0 Baseline を参照してください。
続きはこちら
- 認可コード + PKCE — 上記の流れをシーケンス図とパラメータ用語集で詳説。
- Client Credentials — サービス間通信、エンドユーザなし。
- リフレッシュトークン — ローテーション、再利用検知、猶予期間。
- ID トークン / アクセストークン / userinfo — 似て非なる 3 つのトークン。
- 送信者制約(DPoP / mTLS) — FAPI 2.0 が実際に追加する仕組み。
- FAPI 2.0 入門 — FAPI プロファイルとは何か、PAR / JAR / JARM などの各略号が何をしているか、なぜプロファイルが「OIDC + ベストプラクティス」より勝るのか。