Commit graph

781 commits

Author SHA1 Message Date
Jeremiah Lowin
243f054f65
Include scopes in auth challenges (#4527) 2026-07-18 20:53:52 -04:00
Jeremiah Lowin
998b37f32b
Add server-side identity assertion (SEP-990 ID-JAG) (#4483)
* Add server-side SEP-990 identity assertion (ID-JAG)

* Test SEP-990 identity assertion token endpoint

* Format identity assertion test

* Document SEP-990 identity assertion

* Thread identity_assertion through OIDCProxy

* Harden ID-JAG: authoritative scopes and grant-type enforcement

Scopes for the issued token now derive only from the signed assertion (or server policy when it omits scopes); the client-supplied request scope may narrow but never widen them. Enforce the registered grant-type constraint the SDK check bypassed, and have proxy DCR add the jwt-bearer grant to registered clients when identity assertion is enabled.

* Harden ID-JAG: honor nbf, reject non-object payload, bound jti cache, preserve required_scopes

* Document per-process ID-JAG replay limitation and nbf check

* Harden ID-JAG round 3: resource indicator, non-object header, algorithm config

- Honor RFC 8707 resource on the jwt-bearer grant (invalid_target on
  mismatch), mirroring authorize()'s invariant incl. skip-when-unconfigured
- Reject JSON-array JOSE headers with invalid_grant instead of a 500
- Add IdentityAssertion.algorithm so ES256/PS256 issuers can be verified
  (JWTVerifier otherwise defaults to RS256)

* Bind ID-JAG exchange to the assertion's signed client_id and resource

SEP-990: the IdP signs which client and which resource the assertion was
minted for. With public proxy clients the presented client_id is
self-asserted, so the signed binding is what stops client B redeeming
client A's leaked assertion — and the signed resource claim stops an
assertion for server A being redeemed at server B behind the same IdP.

* Harden ID-JAG round 4: check bindings before jti consumption; validate temporal claims, algorithm, and discovery body

- Move the client_id/resource binding checks into the validator itself,
  before jti is recorded as consumed, so an assertion presented with the
  wrong binding is rejected without burning replay protection for whoever
  it actually belongs to
- Reject non-numeric exp/iat/nbf with invalid_grant instead of a 500
- Validate IdentityAssertion.algorithm at config time (must be an
  asymmetric JWS algorithm verifiable via JWKS)
- Reject a non-object OIDC discovery body with invalid_grant instead of a 500
- Centralize the resource-URL comparison helpers used by both the
  validator and OAuthProxy.authorize()

* Rebase onto httpx2/SDK b2 and harden ID-JAG round 5

- Migrate identity assertion + tests to httpx2 and the local httpx2_mock
  (legacy httpx is now banned; pytest-httpx no longer intercepts)
- Add is_optional to the shared httpx2_mock, mirroring pytest-httpx
- Tighten the algorithm allowlist to JWTVerifier's exact supported set
  (prefix check accepted typos like RS999 -> 500 on first exchange)
- Reject non-string jti before the cache lookup (unhashable -> 500)
- Track revocation for self-contained ID-JAG tokens: revoke_token records
  the jti and load_access_token rejects it until natural expiry
- Dedupe resource-URL helpers: proxy now imports the shared
  normalize_resource_url/server_url_has_query from identity_assertion

* Advertise 'none' token-endpoint auth method when ID-JAG is enabled without CIMD

DCR clients are public, so metadata consumers must see 'none' to use the
advertised jwt-bearer grant; previously only the CIMD path added it.

* Document 2026-07-28 protocol support as a distinct feature catalog

SEP-990 identity assertion leads: the SDK provides the wire contract and
provider hook; FastMCP provides the complete server-side implementation.
Inventories the full modern-era capability set for v4.

* Harden ID-JAG round 6: lazy re-export, dual-form audience, per-issuer algorithms, discovery backoff

- IdentityAssertion re-exported lazily from server.auth (the eager import
  bypassed the package's documented lazy-import boundary)
- Accept the ID-JAG aud both with and without base_url's trailing slash;
  metadata advertises the slashed form, so IdPs echoing it verbatim work
- algorithms={issuer: alg} per-issuer override, mirroring jwks_uris
- OIDC discovery serializes per-issuer and backs off 30s after a failure
  (discovery runs pre-signature, so garbage could amplify into HTTP floods)
2026-07-18 19:52:15 -04:00
nate nowack
f018f68bbf
Expose telemetry attributes on span start (#4487)
* Expose telemetry attributes on span start

🤖 Generated with Codex

* Expose sampling attributes on span start

🤖 Generated with Codex

---------

Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 19:46:19 -04:00
Kevin J Gao
3fdeedb567
Improve DescopeProvider scope discovery and well-known URL support (#4489)
* Improve DescopeProvider scope discovery and well-known URL support

Co-authored-by: Cursor <cursoragent@cursor.com>

* Simplify DescopeProvider scope and URL handling

Co-authored-by: Cursor <cursoragent@cursor.com>

* Make DescopeProvider scope discovery async and lazy

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Generated with Claude Code

* Use generic scope in Descope tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Generated with Claude Code

* Address Descope discovery edge cases

* Deduplicate Descope metadata fallback

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-07-18 16:18:45 -04:00
Jeremiah Lowin
7e077186fc
Clean up task sessions on connection exit (#4535) 2026-07-18 15:45:11 -04:00
Jeremiah Lowin
16383a64d6
Preserve component metadata in response cache (#4521) 2026-07-18 15:42:20 -04:00
Jeremiah Lowin
18b5ab5852
Migrate to MCP SDK v2.0.0b2 (httpx2) (#4503) 2026-07-18 15:12:47 -04:00
Jeremiah Lowin
66c0270bc1
Stabilize upgraded ty checks (#4526) 2026-07-17 17:46:53 -04:00
Jeremiah Lowin
bdb76ef4b2
Clean up disconnected task sessions (#4519) 2026-07-17 17:46:13 -04:00
Jeremiah Lowin
d779414f8a
Screen templated resource parameters for path traversal by default (#4482)
* Add ResourceSecurity screening for templated resources (defaults on)

* Add tests for resource path-security screening

* Document resource path-security; fix ty in tests

* Carry child template security policy through provider mount

Preserve a mounted template's explicit ResourceSecurity (per-param
exemptions or a deliberate opt-out) through FastMCPProviderResourceTemplate.wrap
so the parent read chokepoint honours it instead of the parent default.

* Defer mcp SDK import so fastmcp.resources loads without the [mcp] extra

* Make resource path-security docs examples self-contained and runnable

* Match exempt_params under both hyphen and underscore spellings

Template placeholders like {git-ref} extract as git_ref, so an exemption
written with the natural URI-template spelling never matched.

* Docs: describe net-depth traversal rule accurately; make example runnable

The screening only rejects .. segments that escape the starting depth
(foo/../bar passes) — saying any standalone .. is rejected overstated
the guarantee. Also define DOCS_ROOT so the example runs.
2026-07-17 17:42:48 -04:00
Grégoire
977f02347b
Forward upstream instructions through create_proxy (#4512)
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
2026-07-17 17:29:15 -04:00
Burt Matthews
1fca15abe6
Skip unsupported JWKS keys instead of failing the whole key set (#4515) (#4517) 2026-07-17 17:28:43 -04:00
Jeremiah Lowin
a04f6fd911
Add telemetry off-switch and mcp.protocol.version span attribute (#4481)
* Turn OpenTelemetry instrumentation on by default with explicit off-switch

Add FASTMCP_ENABLE_TELEMETRY setting (default true) and mcp.protocol.version
span attribute for SDK parity.

* Make disabled telemetry a transparent pass-through, not a NoOpTracer

The stock NoOpTracer.start_as_current_span attaches a NonRecordingSpan, hijacking the current OTel context from any enclosing application span. When telemetry is disabled, get_tracer() now returns a non-attaching pass-through tracer so trace.get_current_span() inside handlers still resolves to the caller's span.
2026-07-17 17:02:48 -04:00
Jeremiah Lowin
266c129b62
Test lifespan fires once per process over HTTP (#4480)
* Add regression test: HTTP lifespan fires once per process across sessions

* Drop redundant enter-count assertion at teardown (CodeQL)

* Assert session-manager lifespan entry directly, not user-lifespan count
2026-07-17 17:02:26 -04:00
nate nowack
1d932cc778
Fix Azure scope fallback (#4469) 2026-07-09 15:29:50 -04:00
Jeremiah Lowin
9f251bad00
Forward-port Hugging Face auth provider (#4475) 2026-07-08 20:56:07 -04:00
Jeremiah Lowin
4ad78a60ef
Forward-port HTTP host guard compatibility (#4474) 2026-07-08 20:55:56 -04:00
Jeremiah Lowin
fd5d98bd13
Test: HTTP lifespan fires once per process across sessions (#4470) 2026-07-08 20:55:26 -04:00
Jeremiah Lowin
8ba5b89918
Add server-level cache hints (SEP-2549) (#4464) 2026-07-08 09:10:41 -04:00
Jeremiah Lowin
f30f847e1f
Merge pull request #4449 from PrefectHQ/modernize/path-security
Route skill file access through SDK path-security primitives
2026-07-07 08:00:21 -04:00
Jeremiah Lowin
f0e350942f
Merge pull request #4448 from PrefectHQ/modernize/sampling-deprecation
Deprecate ctx.sample and add clear errors for push features on 2026 connections
2026-07-07 08:00:08 -04:00
Jeremiah Lowin
396fb876d3
Apply ruff-format: drop now-unused imports and reflow 2026-07-07 07:53:11 -04:00
Jeremiah Lowin
6a6fdcb2bb
Repoint tests and examples off removed deprecations
Replaces FastMCP.as_proxy() helper calls with create_proxy(), rewrites the
mount() as_proxy=/prefix= kwarg tests to plain mount() (the params are gone),
and deletes deprecation-only tests for as_proxy() and remove_tool().
2026-07-07 07:53:11 -04:00
Jeremiah Lowin
6621024ce4
Drive the FastMCP lifespan through the SDK session manager (#4446) 2026-07-07 07:49:16 -04:00
Jeremiah Lowin
ac78e6f693
Emit one SERVER span per request and adopt spec-correct error codes (#4445) 2026-07-07 07:49:06 -04:00
Jeremiah Lowin
023a578279
Capture SharedContext for task-enabled Docket servers (#4443) 2026-07-07 07:48:49 -04:00
Jeremiah Lowin
13b9ab80ab
Use a single fastmcp import style in protocol-era tests 2026-07-06 22:06:22 -04:00
Jeremiah Lowin
77131edc00
Don't era-gate server-side sampling handlers on modern connections
The era-gate blocked every ctx.sample/sample_step on a 2026-07-28
connection, but a server-configured sampling handler answers server-side
without the client back-channel. Gate only when the request would hit the
removed client path; force the handler path (client_available=False) on
modern so "fallback" goes straight to the handler instead of a bare
client-attempt failure.
2026-07-06 21:49:18 -04:00
Jeremiah Lowin
05be554e85
Apply ruff formatting to attack corpus tests 2026-07-06 21:32:47 -04:00
Jeremiah Lowin
389e3b78e7
Add path-safety attack corpus tests and document skill file confinement 2026-07-06 21:31:56 -04:00
Jeremiah Lowin
17954f569d
Deprecate ctx.sample/sample_step and era-gate sampling+elicit on modern connections 2026-07-06 21:30:03 -04:00
Jeremiah Lowin
3522a98766
Migrate to MCP Python SDK v2 (#4437) 2026-07-06 17:36:45 -04:00
Jeremiah Lowin
691766b5d0
[codex] Fix OpenAPI resource template requests (#4407) 2026-07-05 19:11:03 -04:00
Jeremiah Lowin
c1b0396c0a
Block IPv6 transition SSRF bypasses (#4426) 2026-07-05 17:52:57 -04:00
Jeremiah Lowin
67527c1f69
Block unsafe OAuth redirect schemes (#4419) 2026-07-05 17:16:10 -04:00
Jeremiah Lowin
57a279928d
Protect streamable HTTP from DNS rebinding (#4405) 2026-07-05 17:11:08 -04:00
Jeremiah Lowin
cccb529f50
Fix DCR redirect URI validation (#4408) 2026-07-05 17:05:13 -04:00
Jeremiah Lowin
de521e651d
Fix versioned auth middleware checks (#4401) 2026-06-28 10:43:34 -04:00
Jeremiah Lowin
feaae683a4
[codex] Fix event store replay isolation (#4402) 2026-06-27 12:49:24 -04:00
Jeremiah Lowin
5de15e0c21
Block NAT64 SSRF bypass (#4400) 2026-06-27 12:21:37 -04:00
Jeremiah Lowin
a8bb1b08c2
Raise fastmcp.ValidationError for invalid tool arguments (#4392)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-27 11:14:20 -04:00
Jacky Su
0668eb7b80
Fix/cimd flow issue (#4206) 2026-06-27 10:57:58 -04:00
Jeremiah Lowin
0cffe41115
fix: validate task tool arguments against declared types (#4373) 2026-06-27 10:03:59 -04:00
Jeremiah Lowin
a612846224
fix: bound default OIDC discovery timeout and expose it on provider wrappers (#4374) 2026-06-24 17:16:18 -04:00
Jeremiah Lowin
ade2b3ff46
fix: bracket IPv6 hosts in server startup log URL (#4372) 2026-06-24 17:15:40 -04:00
Bobby Davidson
7f2d034f4d
Forward IdP auth errors to MCP client instead of showing HTML error page (#4293)
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
2026-06-24 12:09:09 -04:00
Tomasz Czochański
4ce8e2a5d0
Fix: async rate limiting middleware get_client_id callbacks (#4319)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-24 10:27:30 -04:00
Jeremiah Lowin
3b8538e242
Allow private JWT headers (#4290) 2026-06-06 02:23:48 +01:00
Jeremiah Lowin
e58f386bac
Log refresh-token misses in OAuthProxy instead of failing silently (#4276) 2026-06-03 11:22:35 -04:00
René Mulder
0f4f78c464
Fix resource templates with query params on proxied servers (#4251)
Co-authored-by: René Mulder <rene@silverflow.com>
2026-05-31 14:03:49 -04:00