All of the mid-session and step-up auth work
This commit is contained in:
parent
1f31e0f1f8
commit
562bdd00f1
1 changed files with 11437 additions and 1212 deletions
|
|
@ -25,10 +25,11 @@ The [2026-07-28 release candidate](https://blog.modelcontextprotocol.io/posts/20
|
|||
|
||||
| Concern | Mid-session spec | This doc |
|
||||
| ------- | ---------------- | -------- |
|
||||
| **SEP-2350** scope union on 403 step-up | `handleAuthChallenge()` owns union + UX for runtime challenges | Connect-time step-up inherits SDK union after v2 upgrade; mid-session still uses `saveScope(authorizationScopes)` in the challenge handler |
|
||||
| **SEP-2350** scope union on 403 step-up | `handleAuthChallenge()` + `mcpAuth({ forceReauthorization })` for **web remote**, EMA, and **interactive** defer; union persisted on `completeOAuthFlow` success | **Direct streamable HTTP silent step-up:** v2 SDK transport ([#2265](https://github.com/modelcontextprotocol/typescript-sdk/pull/2265)). **Do not** duplicate with client-side fetch intercept or `AuthRecoveryTransport` on TUI/CLI |
|
||||
| **SEP-2207** refresh / `offline_access` | EMA legs 2–3 re-mint; standard OAuth silent refresh | Connect-time scope selection and DCR metadata |
|
||||
| **SEP-2468** `iss` validation | Applies to any interactive re-auth redirect (401 mid-session) | Connect-time callback wiring is the first place to land `iss` passthrough |
|
||||
| **SEP-2352** issuer-bound credentials | Re-register after AS migration may surface as mid-session failure | Storage and `invalidateCredentials` must be correct before mid-session recovery can succeed |
|
||||
| **TUI/CLI mid-session** | [TUI and CLI implementation](v2_auth_mid_session.md#tui-and-cli-implementation): provider + UX; silent retry via v2 SDK | Provider v2 hooks (`invalidateCredentials`, issuer-keyed storage, `application_type`) |
|
||||
|
||||
Implement mid-session auth now. Land auth hardening on the v2 SDK upgrade path without blocking mid-session work — use compatible storage and callback shapes so both tracks merge cleanly.
|
||||
|
||||
|
|
@ -53,8 +54,17 @@ Inspector today uses **`@modelcontextprotocol/sdk` ^1.29.0** (v1 monolith). Auth
|
|||
Connect-time standard OAuth EMA Web remote backend
|
||||
─────────────────────────── ─── ──────────────────
|
||||
SDK auth() + BaseOAuthClientProvider Local wire (ema/) Frozen token stub
|
||||
OAuthStorage keyed by serverUrl IdP OIDC in idpOidc.ts No interactive OAuth
|
||||
completeOAuthFlow(code) only No SDK CrossAppAccess Mid-session → browser
|
||||
OAuthStorage keyed by serverUrl IdP OIDC in idpOidc.ts No interactive OAuth on node
|
||||
completeOAuthFlow(code, iss?) v2 CrossAppAccess optional Mid-session → browser
|
||||
(evaluate vs ema/) fetch intercept (permanent)
|
||||
RemoteClientTransport (permanent)
|
||||
|
||||
TUI / CLI direct (not web remote):
|
||||
──────────────────────────────────
|
||||
StreamableHTTPClientTransport + live OAuthClientProvider in-process
|
||||
v2 SDK: silent 401/403 retry + unionScopes on streamable HTTP (#2265)
|
||||
Inspector: handleAuthChallenge for EMA + interactive defer; TUI/CLI UX only
|
||||
Do NOT: fetch intercept or AuthRecoveryTransport on client SDK transport
|
||||
```
|
||||
|
||||
### What the v2 SDK provides (after upgrade)
|
||||
|
|
@ -62,7 +72,7 @@ completeOAuthFlow(code) only No SDK CrossAppAccess Mid-session
|
|||
| SEP | SDK status (Jun 2026) | Inspector gets |
|
||||
| --- | --------------------- | -------------- |
|
||||
| SEP-2207 | Implemented on v2 `main` ([#2199](https://github.com/modelcontextprotocol/typescript-sdk/issues/2199)) | `offline_access` augmentation in authorize scope for standard OAuth via `auth()` |
|
||||
| SEP-2350 | Open PR [#2265](https://github.com/modelcontextprotocol/typescript-sdk/pull/2265) | `unionScopes()` + 403 retry uses union on streamable HTTP direct transport |
|
||||
| SEP-2350 | Open PR [#2265](https://github.com/modelcontextprotocol/typescript-sdk/pull/2265) | `unionScopes()` + 403 retry uses union on **streamable HTTP direct transport**; SSE unchanged (401 only) |
|
||||
| SEP-2352 | Open PR [#2271](https://github.com/modelcontextprotocol/typescript-sdk/pull/2271) | AS migration detection → `invalidateCredentials` → re-DCR |
|
||||
| SEP-2468 | Open PR [#2272](https://github.com/modelcontextprotocol/typescript-sdk/pull/2272) | `iss` validation in code-exchange path when host passes `iss` |
|
||||
| SEP-837 | Open [#2198](https://github.com/modelcontextprotocol/typescript-sdk/issues/2198) | `application_type` in DCR request body |
|
||||
|
|
@ -76,7 +86,7 @@ completeOAuthFlow(code) only No SDK CrossAppAccess Mid-session
|
|||
| SEP-837 | Ensure web vs TUI/CLI set correct client type (`web` / `native`) in provider metadata or environment | SDK may infer from redirect URI; Inspector must not mis-declare cross-environment |
|
||||
| SEP-2352 | Key `OAuthStorage` credentials by AS `issuer` (not only `serverUrl`); implement `invalidateCredentials` on `BaseOAuthClientProvider`; migrate shared `oauth.json` | Storage is Inspector-owned; SDK calls provider hooks |
|
||||
| SEP-2207 | EMA leg 1 already requests `openid offline_access` (`IDP_OIDC_SCOPES`); verify standard OAuth path after upgrade | EMA bypasses SDK authorize for leg 1 |
|
||||
| SEP-2350 | Mid-session union in `handleAuthChallenge()` + `saveScope(authorizationScopes)`; web/EMA paths bypass SDK transport retry | See [Mid-session auth](v2_auth_mid_session.md) |
|
||||
| SEP-2350 | **Web remote:** mid-session union in `handleAuthChallenge()` (bypasses SDK — proxy architecture). **TUI/CLI direct silent step-up:** v2 SDK transport after #2265. **Interactive defer** (step-up modal / Auth tab confirm): Inspector `setSuppressAuthorizationNavigation` + `mcpAuth({ forceReauthorization })` | See [Mid-session auth § Core API](v2_auth_mid_session.md#core-api--handleauthchallenge) and [TUI and CLI implementation](v2_auth_mid_session.md#tui-and-cli-implementation) |
|
||||
| SEP-2351 | Verify discovery after upgrade; no duplicate discovery logic in Inspector | Uses SDK `discoverOAuthProtectedResourceMetadata` today |
|
||||
|
||||
**Do not duplicate** SDK `auth.ts` logic (RFC 9207 decision table, AS migration edge cases, scope union helpers). Upgrade and wire.
|
||||
|
|
@ -89,15 +99,29 @@ completeOAuthFlow(code) only No SDK CrossAppAccess Mid-session
|
|||
2. **Wire** callback parameters, storage, and client-type metadata in Inspector.
|
||||
3. **Extend** EMA and mid-session paths locally where the SDK has no EMA/XAA API.
|
||||
4. **Upgrade** from `@modelcontextprotocol/sdk` v1 to v2 packages as a gated step — not a silent dependency bump.
|
||||
5. **Do not unify transport layers** between web remote and TUI/CLI — web keeps `RemoteClientTransport` + node fetch intercept; TUI/CLI rely on v2 SDK transport for silent direct retry.
|
||||
|
||||
### Transport ownership (v2 upgrade)
|
||||
|
||||
| Path | Silent 401/403 + RPC retry | Interactive OAuth | Inspector integration |
|
||||
| ---- | -------------------------- | ----------------- | --------------------- |
|
||||
| **Web remote** | `RemoteClientTransport.postSend()` + `pushAuthState` (unchanged) | Browser redirect + resume snapshot | Node fetch intercept only (frozen stub) |
|
||||
| **TUI/CLI direct (streamable HTTP)** | **v2 SDK transport** (`token()` + retry; #2265 union on 403) | Provider `redirectToAuthorization` + host callback | `handleAuthChallenge()` for EMA + defer-navigate; catch `UnauthorizedError` / `SdkHttpError` |
|
||||
| **TUI/CLI direct (SSE)** | v2 SDK 401 retry only | Same as streamable | No 403 step-up on SSE |
|
||||
|
||||
**v2 SDK hooks (direct):** `AuthProvider` with `token()` + optional `onUnauthorized()`; full `OAuthClientProvider` adapted internally. Inspector extends `BaseOAuthClientProvider` toward the v2 contract — **not** a parallel fetch intercept on the client transport.
|
||||
|
||||
**Delete on upgrade:** `core/auth/mcpAuth.ts` body → re-export SDK `auth`; delete `core/auth/scopes.ts` → import `unionScopes` from SDK. **Keep:** `handleAuthChallenge()`, web `RemoteClientTransport`, node `createAuthChallengeInterceptFetch`.
|
||||
|
||||
### Order of work
|
||||
|
||||
| Step | When | Work |
|
||||
| ---- | ---- | ---- |
|
||||
| 1 | **Now (parallel with mid-session auth)** | Compatible prep: callback type includes optional `iss`; storage schema reserves `authorizationServerIssuer`; mid-session `saveScope(union)` per [Mid-session auth](v2_auth_mid_session.md) |
|
||||
| 1 | **Now (parallel with [TUI/CLI mid-session](v2_auth_mid_session.md#tui-and-cli-implementation))** | Compatible prep: callback `iss`; storage schema reserves `authorizationServerIssuer`; provider v2-shaped hooks; direct mid-session e2e baseline; **no** client-side fetch intercept / `AuthRecoveryTransport` |
|
||||
| 2 | **When v2 SDK auth PRs merge** | Upgrade to `@modelcontextprotocol/client`; run existing OAuth integration tests |
|
||||
| 3 | **Immediately after upgrade** | SEP-2468 callback passthrough; SEP-2352 storage + `invalidateCredentials`; SEP-837 client type per environment |
|
||||
| 4 | **Verify** | Smoke scenarios in [v2_auth_smoke_testing.md](v2_auth_smoke_testing.md); add hardening-specific cases |
|
||||
| 3 | **Immediately after upgrade** | SEP-2468 callback passthrough; SEP-2352 storage + `invalidateCredentials`; SEP-837 `application_type` per environment; wire provider `onUnauthorized` → `handleAuthChallenge` where interactive defer needed |
|
||||
| 4 | **TUI/CLI Phase C** | Interactive mid-session UX (Auth tab / callback server) — can overlap step 3 |
|
||||
| 5 | **Verify** | Smoke scenarios in [v2_auth_smoke_testing.md](v2_auth_smoke_testing.md); direct mid-session e2e green on v2 |
|
||||
|
||||
Land order in the SDK (maintainer plan): **SEP-2350 → SEP-2352 → SEP-2468**, with **SEP-837** in the same auth-release series.
|
||||
|
||||
|
|
@ -132,9 +156,12 @@ Land order in the SDK (maintainer plan): **SEP-2350 → SEP-2352 → SEP-2468**,
|
|||
|
||||
#### SEP-2350 — step-up scope accumulation
|
||||
|
||||
- **Connect-time (direct transport):** v2 SDK transport 403 retry after [#2265](https://github.com/modelcontextprotocol/typescript-sdk/pull/2265).
|
||||
- **Mid-session:** `handleAuthChallenge()` computes `authorizationScopes = union(previous, required)`; `saveScope` after success. Standard OAuth step-up = interactive; EMA step-up = silent legs 2–3 when IdP session valid.
|
||||
- **401 re-login:** Replace scope set (not union) — mid-session and connect-time.
|
||||
- **Web remote (mid-session):** `handleAuthChallenge()` union + `pushAuthState` — SDK transport not involved (proxy).
|
||||
- **TUI/CLI direct (silent, streamable HTTP):** v2 SDK transport 403 retry with `unionScopes()` after [#2265](https://github.com/modelcontextprotocol/typescript-sdk/pull/2265).
|
||||
- **Interactive step-up (all clients):** `handleAuthChallenge()` + `mcpAuth({ forceReauthorization })`; `setSuppressAuthorizationNavigation` until user confirms (web modal / TUI Auth tab); `saveScope` on `completeOAuthFlow` success.
|
||||
- **EMA step-up:** silent legs 2–3 when IdP session valid — Inspector `handleAuthChallenge()`, not SDK transport alone.
|
||||
- **401 re-login:** Replace scope set (not union) — all clients.
|
||||
- **SSE:** 401 only; no 403 step-up in v1 or v2 SDK.
|
||||
|
||||
#### SEP-2351 — discovery suffix
|
||||
|
||||
|
|
@ -148,6 +175,8 @@ Land order in the SDK (maintainer plan): **SEP-2350 → SEP-2352 → SEP-2468**,
|
|||
- **Client credentials grant** ([#1225](https://github.com/modelcontextprotocol/inspector/issues/1225)) — separate track.
|
||||
- Full MCP **2026-07-28 stateless transport** migration (separate from auth hardening).
|
||||
- Server-side scope-challenge middleware in Inspector test servers beyond what [Mid-session auth](v2_auth_mid_session.md) requires for 403 fixtures.
|
||||
- **`AuthRecoveryTransport`** or client-side fetch intercept on TUI/CLI SDK transport (defer silent retry to v2 SDK; web node intercept stays).
|
||||
- Unifying web remote and TUI/CLI at the transport wrapper layer.
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
@ -166,12 +195,15 @@ Document manual scenarios in [v2_auth_smoke_testing.md](v2_auth_smoke_testing.md
|
|||
|
||||
| Area | Files |
|
||||
| ---- | ----- |
|
||||
| Upgrade | Root and client `package.json`; import paths v1 → v2 |
|
||||
| Upgrade | Root and client `package.json`; import paths v1 → `@modelcontextprotocol/client` |
|
||||
| Callback | `clients/web/src/App.tsx`, `core/auth/node/oauth-callback-server.ts`, `core/mcp/oauthManager.ts`, `core/mcp/inspectorClient.ts` |
|
||||
| Provider | `core/auth/providers.ts`, `core/auth/browser/providers.ts` |
|
||||
| Provider | `core/auth/providers.ts`, `core/auth/browser/providers.ts` — v2 hooks: `invalidateCredentials`, issuer-keyed storage, `application_type` |
|
||||
| Storage | `core/auth/store.ts`, `core/auth/oauth-storage.ts`, `core/mcp/remote/node/remoteOAuthStorage.ts` (if landed) |
|
||||
| Mid-session overlap | `core/auth/challenge.ts`, `core/mcp/oauthManager.ts` (`handleAuthChallenge`, `saveScope`) — see [Mid-session auth](v2_auth_mid_session.md) |
|
||||
| Tests | `clients/web/src/test/core/auth/`, `clients/web/src/test/integration/mcp/inspectorClient-oauth*.test.ts` |
|
||||
| Web remote (unchanged on v2) | `core/mcp/remote/remoteClientTransport.ts`, `core/mcp/node/authChallengeFetch.ts`, `core/mcp/remote/node/server.ts` |
|
||||
| TUI/CLI | [Mid-session § TUI and CLI](v2_auth_mid_session.md#tui-and-cli-implementation): `clients/tui/src/App.tsx`; `clients/cli/src/cliOAuth.ts`; provider wiring in `core/mcp/inspectorClient.ts` |
|
||||
| Mid-session overlap | `core/auth/challenge.ts`, `core/mcp/oauthManager.ts` (`handleAuthChallenge`, `saveScope`) |
|
||||
| Delete on upgrade | `core/auth/mcpAuth.ts` (re-export SDK), `core/auth/scopes.ts` (use SDK `unionScopes`) |
|
||||
| Tests | `inspectorClient-oauth*.test.ts`, `inspectorClient-oauth-direct-mid-session-e2e.test.ts` (planned) |
|
||||
| Smoke doc | `specification/v2_auth_smoke_testing.md` |
|
||||
|
||||
## Related specs
|
||||
|
|
|
|||
Loading…
Reference in a new issue