Skip to content
go-oidc-provider
Main Navigation go-oidc-provider とは

概要

読む順番

設定の基礎

OAuth 2.0 / OIDC 入門
issuer / 発行者
redirect URI
クライアントの種類
scope と claim
discovery
JOSE 入門 (JWS / JWE / JWK / JWKS / kid)

基本フロー

認可コードフロー + PKCE
リフレッシュトークン
Client Credentials

トークン

ID トークン / アクセストークン
Access token の形式(JWT と opaque)

セッションと同意

session と logout
同意

送信者制約トークン

送信者制約 (DPoP / mTLS) — 選び方
DPoP
mTLS

発展トピック

Device Code(RFC 8628)
CIBA
ブラウザを使わないフロー (CIBA と Device Code)
Token Exchange(RFC 8693)
JARM(署名付き認可レスポンス)
FAPI 2.0 入門

ヘルプ

FAQ
インストール
最小構成 OP
必須オプション
ルーターへのマウント
一覧

基本構成

最小構成 OP
総合バンドル

プロファイル / フロー

セキュリティプロファイルの宣言
FAPI 2.0 Baseline
サービス間通信(client_credentials)
OAuth 2.0(openid なし)
DPoP nonce フロー
Protected resource metadata(RFC 9728)

Grant

Device Code(RFC 8628)
CIBA poll mode
Token Exchange(RFC 8693)
Custom Grant

暗号化 / subject

Pairwise subject
JWE 暗号化

UI

SPA(カスタム interaction)
カスタム同意 UI
カスタムアカウントチューザ UI
マルチアカウントチューザ
SPA 向け CORS
i18n / ロケール

ストレージ

ストレージ構成の選び方
SQL ストア
DynamoDB ストア
Hot / Cold 分離(Redis 揮発)
ストアを自前実装

スコープ / claim

Public / Internal スコープ
Claims リクエスト
Rich authorization requests(RFC 9396)
Grant management

認証

MFA / ステップアップ
既存ユーザーストアの投影
カスタム authenticator

ガバナンス

ファーストパーティ同意スキップ
クライアントオンボーディング
Dynamic Client Registration
Back-Channel Logout

運用

Prometheus メトリクス
Options 索引
エラーカタログ
Audit イベント
アーキテクチャ概観
概要
鍵ローテーション
JWKS エンドポイント
マルチインスタンス展開
observability
バックアップ / DR

標準

RFC 対応一覧
OFCS 適合状況
OFCS 再現レシピ

セキュリティ

セキュリティ方針
設計判断
CVE 回帰マトリクス
時刻ずれとリプレイ猶予
脆弱性報告
リリースノート
変更履歴

日本語

English

日本語

English

Appearance

Sidebar Navigation

概要

読む順番

設定の基礎

OAuth 2.0 / OIDC 入門

issuer / 発行者

redirect URI

クライアントの種類

scope と claim

discovery

JOSE 入門 (JWS / JWE / JWK / JWKS / kid)

基本フロー

認可コードフロー + PKCE

リフレッシュトークン

Client Credentials

トークン

ID トークン / アクセストークン

Access token の形式(JWT と opaque)

セッションと同意

session と logout

同意

送信者制約トークン

送信者制約 (DPoP / mTLS) — 選び方

DPoP

mTLS

発展トピック

Device Code(RFC 8628)

CIBA

ブラウザを使わないフロー (CIBA と Device Code)

Token Exchange(RFC 8693)

JARM(署名付き認可レスポンス)

FAPI 2.0 入門

ヘルプ

FAQ

On this page

同意 ​

同意(consent) とは、ユーザが「このアプリにこの scope を渡してよい」と明示する意思表示です。OIDC Core 1.0 §3.1.2.4 はタイミングを条件付き("OP MUST obtain authorization information from the End-User")に留めていますが、本ライブラリのデフォルトは「クライアントが scope 集合を最初に要求したときに同意画面を出し、その回答を覚える」です。

このページで触れる仕様
  • OpenID Connect Core 1.0 — §3.1.2.4(同意)、§3.1.2.1(prompt)
  • RFC 6749 — §3.3(scope)、§6(refresh)
  • RFC 7009 — トークン失効

メンタルモデル

  • grant とは「ユーザ U が時刻 T に scope 集合 S をクライアント C に認めた」という記録の行。
  • 既存の grant でカバーされない scope を要する authorize フローの最初の 1 回で 同意画面 が表示される。
  • 同じ scope 集合内に収まる以降のフローは、プロンプトを スキップ する。
  • 新しい scope の追加(scope delta)は、その差分だけを尋ねるプロンプトを再度呼び出す。
  • grant を失効させると行が消え、次の authorize フローでは再びプロンプトが出る。

同意画面が表示されるタイミング ​

本ライブラリは authorize フローのたびに次の 4 つを評価します。

grant の状態に対する判定木: prompt=consent、grant が無い、要求 scope が既存 grant の範囲外、のいずれかで同意画面を表示し、それ以外は既存 grant が要求をカバーするためプロンプトなしで認可コードを発行する。リクエストがprompt=consent を含む?(subject, client_id) の既存 grant が無い?要求 scope が既存grant の範囲外?既存 grant が要求をカバー→ スキップして認可コードを発行強制再プロンプト→ 同意画面を表示初回 grant→ 同意画面を表示Scope delta→ 同意画面を表示はいはいはいいいえいいえいいえ
ケース挙動
初回 grant — その (subject, client_id) ペアに対する Grant が存在しない。プロンプト。ユーザは scope の全リストを目にします。送信時、本ライブラリは承認された scope を含む Grant 行を書き込みます。
Scope delta — Grant は存在するが、要求された scope 集合に「過去に承認されていない scope」が含まれる。プロンプト。差分が強調表示されます。ユーザは差分のみ承認、差分を拒否、全体を拒否のいずれかを選べます。承認時に行が更新されます。
強制再プロンプト — リクエストが prompt=consent を持つ。grant の状態に関係なくプロンプト。OIDC §3.1.2.1 が要求する挙動です。
既存 grant が要求をカバー — Grant 行がすべての要求 scope をカバーしており、prompt が none または login(consent ではない)。スキップ。本ライブラリは認可コード発行に直接進み、op.AuditConsentSkippedExisting を発火します。
prompt=none、prompt=login、prompt=consent の違い
  • prompt=none — 「ユーザがログイン済みで同意も整っているなら、フローを静かに完了させる。さもなくばエラーを返す」。SPA の静かな再認証で使う。
  • prompt=login — 「有効なセッションがあっても、ユーザに再認証させる」。これだけでは同意の再プロンプトは強制されない。
  • prompt=consent — 「grant が scope をカバーしていても、同意画面を強制する」。RP が機微な操作の前にユーザに再確認させたいときに有用。

本ライブラリは OIDC Core 1.0 §3.1.2.1 に沿ってこれらを適用します。prompt=none と prompt=login の併用は interaction_required で拒否します。

ファーストパーティクライアント ​

組み込み側によっては、信頼された少数のアプリ — 主力 web クライアント、社内管理コンソール、自社モバイルアプリ — を運用しており、配備時点で操作者が scope カタログを事前承認しているため、同意画面はユーザを煩わせるだけ、ということがあります。こうしたクライアント向けに op.WithFirstPartyClients(ids ...string) は、指定した client_id 値について、Grant 行の有無に関わらず同意画面を スキップ します。要求 scope が操作者の事前承認カタログに含まれている場合に限ります。

重要な注意 2 点。

  1. スキップは記録される。 本ライブラリは Grant 行を通常通り書き込み、op.AuditConsentGrantedFirstParty を発火します — 「このユーザは結局どの scope を承認したのか」という監査の問いには答えられます。変わるのは「ユーザが画面を見たかどうか」だけです。
  2. prompt=consent はスキップを上書きする。 ファーストパーティクライアントが明示的に prompt=consent を要求した場合、同意画面は表示されます。スキップは静かな既定経路のための仕組みであって、上書きの選択肢は残します。

完全な設定(操作者側の scope カタログを含む)は ファーストパーティの使い方 を参照。

ファーストパーティは操作者が宣言するもので、ユーザが宣言するものではない

ユーザは同意フローで「これはファーストパーティアプリです」とは見せられません。信頼の根拠は、操作者が op.WithFirstPartyClients(...) に client_id を列挙していることです。コードパスをエンドツーエンドで管理していないクライアントを列挙してはなりません — そうするとスキップが「告知のない scope 付与」に変わってしまいます。

同意 UI の呼び出し方 ​

プロンプトが必要になると、本ライブラリは組み込み側の op.ConsentUI テンプレート(op.WithConsentUI(...) で登録)に制御を渡します。テンプレートが HTML をレンダリングし、本ライブラリが state、CSRF、__Host-oidc_csrf の double-submit cookie、永続化を担当します。

go
op.WithConsentUI(op.ConsentUI{
    Template: myConsentTemplate, // *template.Template
})

テンプレートには、要求 scope(既存 grant に対する delta があればそれも)、client_id、クライアントメタデータの任意のクライアントロゴ / 表示名、フォームに埋め込む CSRF トークンが渡されます。フォームの POST を受けて、本ライブラリは CSRF を検証し、承認された scope 集合を解析し、Grant 行を書き込み、authorize フローを継続します。

クライアント側で同意を描画する SPA(ログインフォームをすでに扱っている React アプリなど)では、SPA の入口と静的アセットも OP にマウントさせたい場合に op.WithSPAUI(...) を使います。このモードではブラウザは LoginMount/{uid} に着地し、SPA はプロンプトの状態を LoginMount/state/{uid} から取得します。SPA 本体を自前のルータで配信する場合は、低レベルな op.WithInteractionDriver(interaction.JSONDriver{}) 経路を使います。この場合、状態取得エンドポイントは /interaction/{uid} のままです。

WithSPAUI と WithConsentUI はどちらも同意描画面を所有するため相互排他です。コンストラクタは両方同時には受け付けません。route 形と使い分けは SPA カスタムインタラクションの使い方 を参照してください。

同意の失効 ​

ユーザ(または管理者)はいつでも grant を失効できます。失効は 2 つの経路を通ります。

  1. /revoke(RFC 7009) — 単一トークン(refresh または access)を無効化します。これは背後の Grant 行には触れません — 同じ scope での次の authorize フローはまだ grant を見つけ、同意をスキップします。
  2. Grant の失効 — Grant 行の Revoked 列を切り替えます。本ライブラリは Grants と AccessTokens の substore を通じてカスケードします — その grant に連なるすべてのリフレッシュトークン連鎖が無効化され、すべてのアクセストークン shadow row が revoked に切り替わり、JWT AT は OP が応答するすべてのエンドポイント(/userinfo、/introspect)で inactive になります。ユーザの次の authorize フローはカバーする grant を見つけられず、再び同意画面を出します。

カスケードは internal/revokeendpoint、op/store/grant_revocation.go、op/store/cascade.go にまたがって実装されています。各経路はそれぞれの監査イベントを発火するので、ダッシュボードが何が起きたかを再構成できます。end-session カスケード(セッションとログアウト)も同じ仕組みを再利用します。

監査イベント ​

token endpoint と同意フローは、op.WithAuditLogger 経由で 5 つの同意関連監査イベントを発火します。

イベント発火タイミング
op.AuditConsentGrantedユーザが同意フォームを送信し、Grant 行が書き込まれた。
op.AuditConsentGrantedFirstPartyファーストパーティの自動同意が適用された(プロンプトは出していない)。
op.AuditConsentGrantedDelta既存 grant がある状態で、ユーザが scope delta を承認した。
op.AuditConsentSkippedExisting既存 grant が要求をカバーしており、プロンプトをスキップした。
op.AuditConsentRevokedgrant が Revoked に切り替わった。

これらを組み合わせると、SOC ダッシュボードで「ユーザが明示的に同意画面をクリックした」と「操作者が事前承認した静かな経路でこのクライアントが同意を得た」を区別できます — 特定の Grant 行がなぜ存在するのかを振り返る際に有用です。

次に読む ​

  • 使い方: ファーストパーティクライアント — 操作者側の scope カタログ、op.WithFirstPartyClients、監査ポスチャ。
  • 使い方: カスタム同意 UI — op.ConsentUI の設定、テンプレート契約、CSRF の扱い。
  • リファレンス: 監査イベント — 本ライブラリが発火するすべての監査イベントと付随する extras。
Pager
Previous pagesession と logout
Next page送信者制約 (DPoP / mTLS) — 選び方

a personal project by libraz