L1b — gateway connection-level revocation enforcement
Deny any MCP-scoped JWT whose cnf.mcp_pub_b64 (the per-connection X25519 pubkey, RFC 7800 key-binding) is in a revoked-connections feed polled from pinning-webui.
This is the connection-pubkey sibling of the existing jti revocation seam (crates/fula-cli/src/mcp_revocation.rs). It mirrors that seam exactly:
- HTTP source polling
FULA_MCP_CONNECTION_REVOCATION_ENDPOINT → { revoked_pubkeys: [...] } into an in-memory HashSet<String>
- Background refresh loop (
FULA_MCP_CONNECTION_REVOCATION_REFRESH_SECS, default 30, floor 5)
- Fail-open on source outage (keep the previous set on a fetch error — never wipe revocations)
ensure_connection_not_revoked(...) called in middleware.rs::auth_middleware, right beside the jti check
Security invariants
- Non-MCP tokens unaffected: a storage token has no
cnf claim ⇒ extracted pubkey is None ⇒ the check is a no-op. Storage tokens are never denied.
- Disabled by default: all env absent ⇒
None state ⇒ no-op (P12 deploy unchanged until the flags are set).
- Fail-open on source outage (mirrors jti): unreachable endpoint ⇒ keep previous set.
Env contract
FULA_MCP_CONNECTION_REVOCATION_ENABLED — master switch (1/true)
FULA_MCP_CONNECTION_REVOCATION_ENDPOINT — feed URL (GET → { revoked_pubkeys: [...] })
FULA_MCP_CONNECTION_REVOCATION_REFRESH_SECS — poll interval (default 30, floor 5)
FULA_MCP_REVOCATION_INTERNAL_TOKEN — reused jti-family bearer token sent on the feed request when set
PR targets feat/fula-mcp (NOT main).
L1b — gateway connection-level revocation enforcement
Deny any MCP-scoped JWT whose
cnf.mcp_pub_b64(the per-connection X25519 pubkey, RFC 7800 key-binding) is in a revoked-connections feed polled from pinning-webui.This is the connection-pubkey sibling of the existing
jtirevocation seam (crates/fula-cli/src/mcp_revocation.rs). It mirrors that seam exactly:FULA_MCP_CONNECTION_REVOCATION_ENDPOINT→{ revoked_pubkeys: [...] }into an in-memoryHashSet<String>FULA_MCP_CONNECTION_REVOCATION_REFRESH_SECS, default 30, floor 5)ensure_connection_not_revoked(...)called inmiddleware.rs::auth_middleware, right beside the jti checkSecurity invariants
cnfclaim ⇒ extracted pubkey isNone⇒ the check is a no-op. Storage tokens are never denied.Nonestate ⇒ no-op (P12 deploy unchanged until the flags are set).Env contract
FULA_MCP_CONNECTION_REVOCATION_ENABLED— master switch (1/true)FULA_MCP_CONNECTION_REVOCATION_ENDPOINT— feed URL (GET→{ revoked_pubkeys: [...] })FULA_MCP_CONNECTION_REVOCATION_REFRESH_SECS— poll interval (default 30, floor 5)FULA_MCP_REVOCATION_INTERNAL_TOKEN— reused jti-family bearer token sent on the feed request when setPR targets
feat/fula-mcp(NOT main).