Discovery
クライアントは、OP のエンドポイント・署名鍵・対応機能を、ひとつの JSON 文書から知ります。OIDC の OP では OIDC Discovery 1.0 が定める /.well-known/openid-configuration がその文書です。純粋な OAuth 向けには RFC 8414(OAuth Authorization Server Metadata)が /.well-known/oauth-authorization-server で同じ仕組みを定めていますが、本ライブラリが公開するのは openid-configuration だけで、RFC 8414 のメンバーもそこに含めています。本ページでは、この文書の中身を順に見ていきます。
このページで触れる仕様
- OpenID Connect Discovery 1.0
- RFC 8414 — OAuth 2.0 Authorization Server Metadata
- RFC 9126 — Pushed Authorization Requests
- RFC 9449 — DPoP
- FAPI 2.0 Security Profile
なぜ存在するか
discovery がなければ、すべての RP が OP のエンドポイント URL・署名アルゴリズム・対応機能をハードコードすることになり、OP 側の変更のたびに各 RP のコードを直す必要が出ます。discovery があれば、RP が知るべきなのは issuer の URL(https://op.example.com)だけです。
Discovery 文書の中身
Cache-Control: public, max-age=3600 が付くので、RP が再取得するのは多くても 1 時間に 1 回程度です。下の表は、最初に目にするフィールドの一覧です。対応する機能が設定されていれば、本ライブラリがそれぞれ出力します。エンドポイントの URL は絶対 URL で、mount prefix(既定は /oidc)の下に置かれます。例: https://op.example.com/oidc/auth。
| フィールド | 内容 |
|---|---|
issuer | OP の正規識別子。署名されるすべてのトークンの iss と同じ文字列です。RP は byte 単位で比較します。 |
authorization_endpoint | /auth の URL — ブラウザがログインのためにリダイレクトされる先。 |
token_endpoint | /token の URL — RP が code やリフレッシュトークンを交換する場所。 |
userinfo_endpoint | /userinfo の URL — RP がアクセストークンを使って最新の claim を取得する場所。 |
jwks_uri | JWKS の URL — OP の公開署名鍵を JWK Set として公開する URL。 |
introspection_endpoint | /introspect の URL(RFC 7662)— introspection 機能を組み込んだ場合のみ。 |
revocation_endpoint | /revoke の URL(RFC 7009)— revocation 機能を組み込んだ場合のみ。 |
end_session_endpoint | /end_session の URL — RP-Initiated Logout でブラウザをリダイレクトする先。認可エンドポイントがある場合だけ出力されます。 |
backchannel_logout_supported | 認可エンドポイントがあれば true。OP は Back-Channel Logout の logout token を送れます。 |
registration_endpoint | /register の URL(RFC 7591)— op.WithDynamicRegistration(...) を組み込んだ場合のみ。 |
pushed_authorization_request_endpoint | /par の URL — PAR 機能(RFC 9126)を有効化した場合のみ。 |
device_authorization_endpoint | /device_authorization の URL — device code grant を組み込んだ場合のみ。 |
backchannel_authentication_endpoint | /bc-authorize の URL — CIBA grant を組み込んだ場合のみ。 |
grant_types_supported | /token で受け付ける grant 種別: authorization_code、refresh_token、client_credentials、… |
response_types_supported | 認可エンドポイントが受け付ける response type。ブラウザ認可を使う構成では code のみ(OIDC Core の "code flow")を広告します。client_credentials だけの OP では認可エンドポイントを mount しないため、空配列になります。 |
response_modes_supported | 認可エンドポイントの応答方式: query、form_post、加えて JARM 有効時は query.jwt、fragment.jwt、form_post.jwt、jwt。 |
authorization_response_iss_parameter_supported | 常に true。すべての認可応答に iss が付きます(RFC 9207)。 |
id_token_signing_alg_values_supported | ID トークンの署名に使う JWS アルゴリズム。本ライブラリは OP が署名に使う 1 つのアルゴリズムだけを公開します。既定は ES256、op.WithSigningAlgorithm(op.AlgRS256) を指定した場合は RS256 です。 |
request_parameter_supported / request_uri_parameter_supported | JAR を有効にした場合だけ true。それ以外は false。 |
request_object_signing_alg_values_supported | JAR の request= パラメータで受理する JWS アルゴリズム: RS256、PS256、ES256、EdDSA。FAPI profile では PS256、ES256、EdDSA に絞られます。JAR を有効にした場合のみ出力。 |
token_endpoint_auth_methods_supported | クライアントが /token で認証する方式。既定のリストには client_secret_basic、client_secret_post、private_key_jwt、none が含まれ、FAPI profile では絞り込まれます。introspection と revocation の auth method リストからは、confidential caller を必須とするため none が意図的に除かれます。feature.MTLS を有効にすると、リストには tls_client_auth と self_signed_tls_client_auth も加わります。mTLS エンドポイントの metadata は mtls_endpoint_aliases で別に広告します。 |
code_challenge_methods_supported | PKCE 変換。本ライブラリが広告するのは S256 のみ。 |
subject_types_supported | public と、op.WithPairwiseSubject(...) を組み込んだ場合は pairwise。 |
claims_supported | OP が返せる claim。op.WithClaimsSupported(...) を渡さない限り出力されません。ユーザストアの中身はライブラリには分からないためです。 |
scopes_supported | public な scope。標準の OIDC scope と、op.WithScope(...) で public として登録した scope です。private な scope は載りません。 |
dpop_signing_alg_values_supported | DPoP 機能(RFC 9449)を有効化した場合のみ。 |
require_pushed_authorization_requests | PAR を必須とするプロファイル(FAPI 2.0 系)でのみ true として出力。 |
acr_values_supported | acr_values で受け付ける認証コンテキストクラス。op.WithACRValuesSupported(...) を設定した場合のみ出力。ACR ポリシーが解決できない値は op.New が拒否するため、AAL URI 以外の値は op.WithACRPolicy で宣言します。 |
claims_parameter_supported | 既定は true。OIDC §5.5 の claims request を広告・処理しない場合は op.WithClaimsParameterDisabled() を渡す。 |
authorization_details_types_supported | authorization_details で受理する RFC 9396 の type 値。op.WithAuthorizationDetailTypes(...) を組み込んだときのみ出現。 |
grant_management_endpoint | grant management エンドポイントの URL。op.WithGrantManagement(...) を組み込んだときのみ出現。 |
grant_management_actions_supported | OP が受理する grant management アクション(create / replace / merge / query / revoke)。grant_management_endpoint と一緒に出現。 |
grant_management_action_required | WithGrantManagement(op.GrantManagement{..., ActionRequired: true}) のときのみ true として出力。認可リクエストは grant_management_action を必ず含める必要がある。 |
introspection_endpoint_auth_signing_alg_values_supported | /introspect の client_assertion で受け付ける JWS アルゴリズム。introspection 機能を組み込み、そのエンドポイントの認証方式に assertion 系の方式(private_key_jwt)が含まれる場合のみ出力。 |
revocation_endpoint_auth_signing_alg_values_supported | /revoke の client_assertion で受け付ける JWS アルゴリズム。revocation 機能を組み込み、そのエンドポイントの認証方式に assertion 系の方式(private_key_jwt)が含まれる場合のみ出力。 |
prompt_values_supported | 認可エンドポイントが受け付ける prompt の値: none、login、consent、select_account。create は LoginFlow.Registration を設定した場合のみ加わります。 |
authorization_grant_profiles_supported | urn:ietf:params:oauth:grant-profile:id-jag。experimental: 信頼する ID-JAG issuer が 1 つ以上ある場合のみ出力(ID-JAG)。issuer 自体は公開されません。 |
identity_chaining_requested_token_types_supported | urn:ietf:params:oauth:token-type:id-jag。experimental: op.WithIDJAGIssuance(...) を組み込んだ場合のみ出力(ID-JAG)。 |
client_id_metadata_document_supported | op.WithClientIDMetadataDocuments(...) を組み込むと true。HTTPS の client_id をそのメタデータドキュメントとして解決します。experimental。無効なら出力されません(MCP 認可サーバ)。 |
op.WithProtectedResources(...) を組み込むと、OP はさらに RFC 9728 protected-resource metadata を /.well-known/oauth-protected-resource で配信します。登録リソースごとに 1 つの文書があり、openid-configuration のフィールドではなく独立した well-known 文書です。
_supported は広告であってポリシーではない
_supported のリストは、OP が 受け付ける ものであって、すべてのクライアントがそれらを使う必要があるわけではありません。クライアントは部分集合を選んでよく、OP はリストにないものを拒否します。
クライアント側での使い方
典型的な RP SDK は初回起動時に次の動きをします。
GET https://op.example.com/.well-known/openid-configuration- レスポンスをキャッシュする。保持してよいのは OP が返す
max-age(3600 秒)まで。 - キャッシュした文書から、エンドポイント・対応アルゴリズム・対応機能を読み取る。
- キャッシュが切れたとき、または未知の
kidで署名検証に失敗したとき(多くは OP が鍵をローテーションした合図)に再取得する。
本ライブラリは次の 2 点で RP を助けます。同じ設定である限り discovery 文書の内容は変わらないので、RP は長めにキャッシュできます。鍵ローテーション中は、組み込み側が op.WithJWKSRotationActive(predicate) で知らせると、JWKS エンドポイントが max-age=3600 から max-age=300, must-revalidate に切り替わり、再取得した RP が新しい鍵をすぐ見つけられます。
文書は一度だけ組み立てられる
OP は provider の作成時に文書を組み立てて JSON にシリアライズし、以後は同じ JSON のボディを返し続けます。同じ設定のインスタンスはすべて同一の byte 列を返すので、古さの問題は RP 側のキャッシュに限られます。RP がキャッシュ済みの JWKS をどのくらい使い続けてよいかは 鍵ローテーション を参照してください。
本ライブラリでの構築方法
discovery は op.New の時点で、組み込まれた機能集合から一度だけ構築されるので、実行時に内容がずれることはありません。組み込み側が PAR を組み込んでいなければ pushed_authorization_request_endpoint は出力されず、require_pushed_authorization_requests も登場しません。組み込み側が op.WithProfile(profile.FAPI2Baseline) を組み込んでいれば FAPI の絞り込みが適用されます — token_endpoint_auth_methods_supported は FAPI が許可する集合に絞り込まれ、require_pushed_authorization_requests=true が出現し、introspection / revocation の auth method リストは none を除いた絞り込み後の同じリストからコピーされます。認可エンドポイントとブラウザ専用の metadata は、ブラウザ認可を必要とする grant が設定されている場合だけ出力されます。そのため client_credentials だけの OP では authorization_endpoint、end_session_endpoint、backchannel_logout_supported が省略され、response_types_supported: [] は残ります。
WithDiscoveryMetadata(DiscoveryMetadata{UILocalesSupported: ...}) でロケールを明示的に広告する場合も、構築時の契約が適用されます。広告するロケールが登録済みのリゾルバから提供されていなければ op.New が失敗し、UI が提供できないロケールを discovery に出すことを防ぎます。
プロファイルごとの文書の形は golden test で固定しているので、discovery の内容とハンドラの実際の挙動が気付かれずに乖離することはありません。背景は 設計判断 #12 を参照してください。
文書は mount prefix の外側、/.well-known/openid-configuration で配信されます。path を持つ issuer では、同じ文書を issuer 相対のパスでも配信します。詳細は Issuer を参照してください。
本ライブラリが広告 しない もの
本ライブラリは、意図的に discovery 文書を絞り込んでいます。
nonealg は出さない。id_token_signing_alg_values_supportedとrequest_object_signing_alg_values_supportedにnoneは含まれません。これは/tokenに列挙される クライアント認証方式のnoneとは別の話で、noneは署名アルゴリズムとしては使いません(JOSE 基礎 と 設計判断 #11 を参照)。- ID トークンに HMAC 系 alg を出さない。
HS256/HS384/HS512は広告しません。alg-confusion 攻撃はこれらに到達できることが前提なので、本ライブラリは到達できる経路をそもそも作りません。 - JAR を組み込まない限り、request object への対応を示さない。 JAR がなければ
request_parameter_supportedとrequest_uri_parameter_supportedはfalseで、request object のアルゴリズム一覧も出力されません。pushed_authorization_request_endpointは PAR を組み込んだときだけ登場します。 claims_parameter_supportedの既定はtrueだが、無効化できる。op.WithClaimsParameterDisabled()を渡すと、discovery 文書は OIDC §5.5 対応を広告せず、authorize / PAR は不正な JSON の拒否後にclaimspayload を無視します。frontchannel_logout_supportedもcheck_session_iframeも出さない。 Front-Channel Logout 1.0 / Session Management 1.0 は実装していないため、discovery 文書はそれらについて沈黙します。組み込み側は代わりに Back-Channel Logout 1.0 を使います — 設計判断 #5 を参照。
Discovery は契約面
_supported の各配列は、その値を受け付けるという約束です。値を増やせば契約が広がり、減らせば狭まります。RP は、必要とするアルゴリズムを広告しなくなった OP との通信を拒否することがあります。discovery 文書の変更は、公開 API の変更と同じ重さで扱ってください。
次に読む
- 運用: JWKS — JWK Set がどう見え、本ライブラリがどう serve しているか。
- 運用: 鍵ローテーション — RP のキャッシュを壊さずに署名鍵をローテーションする方法。
- リファレンス: オプション — discovery 文書に現れるすべての
op.With...オプション。