[v2] OAuth discovery validates any /.well-known/openid-configuration document as OIDC, rejecting conforming RFC 8414 metadata
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 58/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- typescript
調査の方向性
まず client/dist/index.mjs の discoverAuthorizationServerMetadata() と関連するスキーマから始め、次に提供された fetchFn の再現を RFC 8414 ドキュメントに対して実行します。候補の失敗とスキーマ選択を追跡し、適合する OAuth メタデータドキュメントが /.well-known/openid-configuration で受け入れられるか、または issuer の検証を維持したまま別の候補へ discovery が継続されることを確認します。
索引モデルが issue の本文から書いたものです。
説明
What happened?
discoverAuthorizationServerMetadata() picks its validation schema from which well-known filename resolved, not from the document that came back. Every openid-configuration candidate is typed "oidc", so anything served there is validated against OpenIdProviderDiscoveryMetadataSchema:
// client/dist/index.mjs (2.0.0)
const parsed = type === "oauth"
? OAuthMetadataSchema.parse(await response.json())
: OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
That schema requires jwks_uri, subject_types_supported and id_token_signing_alg_values_supported — three fields OpenID Connect Discovery 1.0 requires and RFC 8414 does not. So a plain OAuth 2.0 authorization server (no ID tokens, no JWKS, no sub) that publishes RFC 8414 metadata at /.well-known/openid-configuration is rejected:
[
{"expected":"string","code":"invalid_type","path":["jwks_uri"],"message":"Invalid input: expected string, received undefined"},
{"expected":"array","code":"invalid_type","path":["subject_types_supported"],"message":"Invalid input: expected array, received undefined"},
{"expected":"array","code":"invalid_type","path":["id_token_signing_alg_values_supported"],"message":"Invalid input: expected array, received undefined"}
]
Two things make this fatal rather than cosmetic:
- RFC 8414 §5 explicitly permits that filename for general OAuth metadata. The server is conforming; the client is not.
- The parse throws instead of continuing the candidate loop. Every other failure in that loop (
continueon 4xx/502,continueon a CORS failure) falls through to the next candidate. A schema failure abortsdiscoverAuthorizationServerMetadata()entirely, so no later candidate is tried and the whole connection fails.
Reported downstream at modelcontextprotocol/inspector#2172 against a real server (https://misc.poodll.com/mod/minilesson/mcp.php, a plain OAuth 2.0 AS whose resource lives under a path). Reproduced independently against @modelcontextprotocol/[email protected] with an injected fetchFn, and again against a local test server that serves RFC 8414 metadata only at /.well-known/openid-configuration.
Two smaller things noticed in the same code path, mentioned here rather than as separate issues since a fix will likely touch both:
OpenIdProviderDiscoveryMetadataSchemais az.object(...), not az.looseObject(...)likeOAuthMetadataSchema. So a successful OIDC parse strips RFC 8414 fields that are not in the OIDC shape —revocation_endpointandintrospection_endpointamong them — from the returned metadata.- The doc comment on
discoverAuthorizationServerMetadatasays it "attempts RFC 8414 OAuth metadata discovery first / if OAuth discovery fails, falls back to OpenID Connect Discovery", which is what the URL ordering does but not what the schema selection does.
What did you expect?
A document should be validated by what it is, not by the filename it was found under. Concretely, either:
- try
OAuthMetadataSchemaand fall back toOpenIdProviderDiscoveryMetadataSchema(or vice versa) regardless of the candidate'stype—OAuthMetadataSchemais a loose object, so it accepts a full OIDC document without dropping any of its fields; or - treat a schema failure like the other per-candidate failures and
continueto the next candidate rather than throwing out of the whole function.
Either way, issuer validation (RFC 8414 §3.3 / OIDC Discovery §4.3) should stay exactly as it is.
Code to reproduce
import { discoverAuthorizationServerMetadata } from '@modelcontextprotocol/client';
// A plain OAuth 2.0 AS: RFC 8414 metadata, served only at the OIDC well-known path.
const METADATA = {
issuer: 'https://as.example.com',
authorization_endpoint: 'https://as.example.com/oauth/authorize',
token_endpoint: 'https://as.example.com/oauth/token',
response_types_supported: ['code'],
grant_types_supported: ['authorization_code', 'refresh_token'],
code_challenge_methods_supported: ['S256'],
};
const fetchFn: typeof fetch = async input => {
const url = String(input);
if (url === 'https://as.example.com/.well-known/openid-configuration') {
return new Response(JSON.stringify(METADATA), {
status: 200,
headers: { 'content-type': 'application/json' },
});
}
return new Response('not found', { status: 404 });
};
// Throws a ZodError for jwks_uri / subject_types_supported /
// id_token_signing_alg_values_supported. Expected: the RFC 8414 document.
await discoverAuthorizationServerMetadata('https://as.example.com', { fetchFn });
SDK version
@modelcontextprotocol/[email protected] (with @modelcontextprotocol/[email protected])
- 主要言語
- TypeScript
- スター
- 13.5k
- フォーク
- 2.3k
- 平均マージ
- 1日 22時間
- マージ済み PR(30日)
- 52
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
modelcontextprotocol/typescript-sdk のほかの issue
-
Stateless 405 response omits the Allow header対応中かも @jstar0 が 1 日前に担当しました。 オープンv2
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
modelcontextprotocol/typescript-sdk#2970 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
[v2] @modelcontextprotocol/server inlines fast-uri 3.1.0, which has 9 published advisories対応中かも @Andiii208 が 1 日前に担当しました。 オープンv2
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
modelcontextprotocol/typescript-sdk#2966 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
v1 v2
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
modelcontextprotocol/typescript-sdk#2946 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信
-
[v2] URI template reserved expansions encode existing %HH sequences again対応中かも @takagibit18 が 7 日前に担当しました。 オープンv1 v2
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
modelcontextprotocol/typescript-sdk#2920 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[v2] URI template strict expansions leave !'()* unencoded対応中かも @takagibit18 が 7 日前に担当しました。 オープンv1 v2
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
modelcontextprotocol/typescript-sdk#2919 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
modelcontextprotocol/typescript-sdk の issue をすべて見る
似ている issue
-
check:passed streams:add
難易度 1/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 2 日以内に返信
-
beta technical-medium ui
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
walletbeat/walletbeat#1625 ·
メンテナーはふだん 1 日以内に返信
-
Good First Issue hacktoberfest
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
hiero-ledger/hiero-sdk-js#4489 ·
メンテナーはふだん 1 日以内に返信
-
[Bug] The clients language filter cannot select the rows the page labels as unknown対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
apache/rocketmq-dashboard#6103 ·
メンテナーはふだん 4 日以内に返信
-
Bug
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
payloadcms/payload#18652 ·
メンテナーはふだん 1 日以内に返信