Skip to content

OAuth 2.0 / OpenID Connect 入門

認証・認可がはじめての方には、関連する規格は略語の羅列に見えるかもしれません: OAuth、OIDC、JWT、OP、RP、RS、PAR、JAR、JARM、DPoP、mTLS、PKCE、FAPI… ですが安心してください。ロールは 3 つだけ で、ほとんどの規格はこの 3 ロール間のフローを少しずつ強化したものです。

このページで触れる仕様

3 つのロール

ログインの実際のステップ(/authorize への redirect、code 交換、トークン取得)は後段の 認可コード + PKCE フロー で詳述します。まずは「誰が何を担当しているか」を押さえてください。

同じソフトが複数のロールを兼ねることもある

たとえば「Backend for Frontend」は、ユーザをログインさせる RP であると同時に、SPA からアクセストークン付きで呼ばれる RS でもあります。

OAuth 2.0 と OpenID Connect の違い

OAuth 2.0 は 認可の委任 を担う規格です — 「Alice のアプリが、サービス X 上の Alice のデータを読む許可をもらう」。OAuth 2.0 単独では、アプリ側に Alice が誰なのか は伝わりません。あくまで不透明なアクセストークンを渡すだけです。

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 とは

JWT(JSON Web Token、RFC 7519)は header.payload.signature の 3 つを . で繋いだ base64url 文字列です。header と payload は JSON で、signature は受け手が公開鍵で発行者を暗号学的に検証するための部分です。

OIDC では ID トークンは常に JWT、本ライブラリのアクセストークンも JWT で発行されます。JSON が読めて署名が検証できるなら JWT は読めます — 独自バイナリ形式は登場しません。

Opaque と JWT の違い
  • Opaque token — 受け手にとっては意味のないランダム文字列。中身を知るには発行元の introspection エンドポイント(RFC 7662)に問い合わせ、対応する行を引きに行く必要があります。
  • JWT — 自己記述的。中身がトークンにエンコードされていて、署名の検証だけで(オフラインで)受け手が中身を信用できます。

トレードオフは「リクエストごとに OP に問い合わせるか」対「OP からきめ細かい失効を制御しづらくなるか」のどちらを取るかです。本ライブラリの折衷案は tokens を参照してください。

どちらを使えばいい?
  • 純粋な OAuth 2.0: 「このトークンは POST /things を呼べる」だけが言えれば良い API。サービス間通信でよく使われます。
  • OIDC: 人間がログインして、アプリが「こんにちは Alice」と言いたいケース。Web・モバイルのログインはほぼすべて OIDC です。

go-oidc-provider はデフォルトで OIDC(openid scope 必須)として動作し、op.WithOpenIDScopeOptional() で純粋 OAuth 2.0 にも切り替えられます。

出てくる 4 種類のトークン

トークン寿命何のためのもの行き先
認可コード数十秒(既定 60 秒)1 回限りの不透明な文字列。server-to-server: RP → OP /token
アクセストークン数分(既定 5 分)API を呼ぶときの Authorization: Bearer … に乗せる。JWT または opaque。RP → RS。
リフレッシュトークン数日〜数週間(既定 30 日)長寿命。再認証なしに新しいアクセストークンを取得するために使う。RP → OP /token
ID トークン数分(アクセスに追従)ユーザが誰かを証明する署名付き JWT。API には送らないOP → RP、RP 内で消費。

ID トークンを Bearer に乗せない

よくある落とし穴です。ID トークンの audience は RP であって RS ではありません。API に Authorization: Bearer で送ると技術的には通ってしまいますが、意味的には誤り — RP の機微情報(email など)をユーザが触る全 API に晒すことになります。

API にはアクセストークンを使ってください。 RFC 7662 の introspection、もしくは RFC 9068 の self-contained JWT として検証します。

最もよく見かけるフロー: 認可コード + PKCE

「+ PKCE」(code_challenge / code_verifier で示される部分)は、悪意あるアプリが認可コードを横取りすることを防ぐ仕組みです。詳しくは 認可コードフロー + PKCE で扱います。

このサイトでよく出てくる用語

用語意味
Scope半角スペース区切りの権限リスト(例: openid profile email)。ユーザがこれに同意します。
Claimトークン内のフィールド(subemailemail_verified など)。
Consent(同意)「このアプリはあなたのメールを読みたいと言っています」画面のこと。OP が記録し、同じ scope の次回ログインはスキップします。
Audience(audトークンの宛先。ID トークンは aud = client_id、アクセストークンは aud = resource server です。
Issuer(issトークンに署名した OP。RP も RS も自分の期待値と一致するか確認します。
JWKSJSON Web Key Set。OP の公開鍵集合で、/jwks から取得します。RP は ID トークンの検証に使います。
Discovery document/.well-known/openid-configuration。エンドポイント、対応 scope、対応 alg などをまとめた JSON カタログ。

FAPI 2.0 が追加するもの

金融グレード・医療グレードの OP を作るなら、OIDC の上に FAPI 2.0 を乗せる必要があります。送信者制約付きトークン(DPoP / mTLS)、PAR(authorize 要求を先に server-to-server で送る)、JAR(要求自体を署名 JWT にする)、より絞られた alg allow-list が要求されます。本ライブラリではプロファイル指定 1 行で有効化できます。

go
op.WithProfile(profile.FAPI2Baseline)

略号を一通り解説した入門は FAPI 2.0 入門 にあります。DPoP / mTLS の仕組みは 送信者制約 を、フル構成は ユースケース: FAPI 2.0 Baseline を参照してください。

続きはこちら