PATTERN Cited by 1 source
Layered JWT + mesh auth¶
Pattern¶
Layered JWT + mesh auth is the two-layer authorization shape for agent traffic inside an enterprise mesh: an end-user JWT authenticates + coarsely authorizes the human on whose behalf an agent is acting, and a SPIFFE-style mesh identity authenticates the calling workload. Both travel on every request; both are enforced; they compose.
Canonical wiki statement (Pinterest, 2026-03-19):
"At runtime, almost every MCP call is governed by two layers of auth: end-user JWTs and mesh identities." (Source: sources/2026-03-19-pinterest-building-an-mcp-ecosystem-at-pinterest)
Two layers, two jobs¶
Layer 1 — end-user JWT (who is the human?)¶
- Client (AI chat web, IDE plugin, chat-platform AI bot) performs OAuth against the enterprise's internal auth stack.
- OAuth issues a JWT with the user's identity + business-group membership + optional roles.
- The client carries the JWT on every MCP call.
- Envoy at the mesh ingress validates the JWT and maps it to headers —
X-Forwarded-User,X-Forwarded-Groups, and related. - Envoy enforces coarse-grained policies at the server-reachability altitude ("AI chat webapp in prod may talk to the Presto MCP server, but not to experimental MCP servers in dev namespaces").
Layer 2 — mesh identity (who is the calling workload?)¶
- Each workload has a SPIFFE-style mesh identity issued by the service mesh (e.g. SPIRE + Envoy SDS, or a company-specific mesh-identity substrate).
- The mesh validates workload-to-workload traffic independently of end-user JWT.
- For low-risk read-only scenarios with no end user in the loop, mesh identity alone is sufficient: the server authorizes based on the calling service's mesh identity.
Optional sub-layer — in-process per-tool decorator¶
"Inside the server, tools use a lightweight @authorize_tool(policy='…') decorator to enforce finer-grained rules (for example, only Ads-eng groups can call a get_revenue_metrics, even if the server itself is reachable from other orgs)."
The decorator reads the headers Envoy wrote (X-Forwarded-User / X-Forwarded-Groups) and enforces per-tool policy. See patterns/per-tool-authorization-decorator.
Why layered — single-layer designs fail¶
- JWT alone — covers the human but not workload-to-workload calls (the MCP server calling another internal service). Also no defense-in-depth: JWT compromise is catastrophic.
- Mesh identity alone — no human attribution; can't enforce "this user's role requires data access" (the business-group gating axis).
- OAuth-per-server (the MCP spec's shape) — per-server consent dialogs + per-server tokens. High user friction. Pinterest explicitly rejects this for internal agents: "users already authenticate against our internal auth stack when they open a surface like the AI chat interface, so we piggyback on that existing session."
Enforcement altitudes¶
| Altitude | What's enforced | Where |
|---|---|---|
| Transport | JWT valid + signed | Envoy |
| Mesh | Calling workload identity | Service mesh (SPIFFE / SPIRE) |
| Server-reachability | Can user reach this server | Envoy policy using header-mapped JWT claims |
| Session | Can user open a session (business-group gate) | In-server or registry pre-flight |
| Tool-call | Can user call this specific tool | @authorize_tool(policy='…') decorator |
Each altitude is a checkpoint; each can fail-closed independently; compromise of any single layer does not bypass the others.
The contrast with per-server OAuth¶
The MCP authorization spec defines an OAuth 2.0 flow where users authenticate with each MCP server separately — consent screens, per-server token management, per-server authorization code exchanges. Pinterest's posture: "There is no additional login prompt or consent dialog when a user invokes an MCP tool. Envoy and our policy decorators handle authorization transparently in the background, giving us fine-grained control over who can call which tools without surfacing the complexity of per-server authorization flows to the end user."
Trade-offs:
- Per-server OAuth — higher user transparency (every server explicitly consented to), higher friction (N consent dialogs), less intra-org uniformity.
- Layered JWT + mesh — piggyback on existing SSO (zero incremental friction), enterprise-wide policy consistency, assumes trust in the enterprise auth stack.
The layered pattern is a deliberate enterprise integration choice, not a rejection of the spec — the spec is for cross-org / public MCP; layered JWT + mesh is for inside-the-org MCP.
Seen in¶
- sources/2026-03-19-pinterest-building-an-mcp-ecosystem-at-pinterest — canonical wiki instance. Pinterest's MCP ecosystem at 66,000 invocations/month across 844 MAUs, gated entirely by this layered shape.
Related¶
- systems/envoy — the JWT-validation + header-mapping point.
- systems/model-context-protocol — the protocol the pattern secures.
- systems/pinterest-mcp-registry — the registry whose pre-flight API participates in session-level enforcement.
- concepts/workload-identity — the mesh-identity concept.
- concepts/business-group-authorization-gating — the session-level narrowing the JWT claims enable.
- concepts/authorization-vs-authentication-token — separation-of-concerns adjacent framing.
- concepts/fine-grained-authorization — the tool-call altitude this pattern culminates in.
- patterns/jwt-tenant-claim-extraction — sibling JWT-claim-extraction pattern.
- patterns/per-tool-authorization-decorator — the fine-grained enforcement sub-layer.
- patterns/hosted-mcp-ecosystem — the umbrella pattern this is a constituent of.
- patterns/central-proxy-choke-point — choke-point pattern (Envoy + registry form a choke point).