Authentication
Quick summary
Authentication depends on the server: local protect MCP has workspace controls, remote Gateway forwards a bearer token, and local Rust commerce MCP can use development credentials.
Never use development user headers in production and never pass a seller credential to a public endpoint.
Three distinct credential mechanisms across the MCP surface — pick by server, and never cross the public/private boundary.
At a glance
| Server | Credential | How it's carried |
|---|---|---|
yp-mcp (local protect) | none — no upstream API | n/a (the workspace boundary + approved:true are the gates) |
yetdapay-mcp-gateway (remote) | client's Authorization: Bearer <token> request header | forwarded verbatim to seller-scope upstream endpoints only |
yetdapay-mcp (Rust, local) | env: YETDAPAY_MCP_TOKEN (bearer, wins) or YETDAPAY_DEV_USER (X-Dev-User header) | attached to seller-scope requests by the server process |
The public/private rule (all servers)
- Seller-scope tools fail closed when no credential exists: gateway → tool error
{code:"UNAUTHORIZED"}before any upstream call; Rust server →UNAUTHORIZEDwhen neither env var is set. - Public tools and all
/public/**upstream calls never carry credentials —yetdapay_integration_assets_getandyetdapay_license_verifyare public-scope; the gateway's public request path attaches noAuthorizationheader by contract. - Only
public_id(intpub_…) is safe to embed in visitor-facing code — never seller credentials or internal ids.
Bearer token vs dev-user
Two different upstream auth modes exist because the two backends differ:
| Backend | Login returns | Credential the CLI/MCP sends |
|---|---|---|
be-cloudflare Worker | {ok, token(JWT), …} | Authorization: Bearer <jwt> |
be/ Axum | {ok, role, …} — no token | X-Dev-User: <email> (dev-auth deployments only) |
The gateway forwards whatever header the client sends — if you point it at an Axum backend, Authorization: Bearer won't authenticate dev identities; use X-Dev-User-style deployments locally or go through the Rust server with YETDAPAY_DEV_USER. Production backends reject X-Dev-User with 401.
yp auth login handles this split automatically: it stores {type:"bearer"} or {type:"dev-user"} based on what the backend actually returned — see CLI Configuration.
What is not here
- No PoP/entitlement auth on the MCP layer. The
Entitlement/DPoPheader pair is the buyer device-binding plane for/licenses/{capability,execute,status}— the license SDK handles it (Device Binding), not the MCP servers. - No token storage on the gateway. The gateway is stateless — the client holds the credential; it is forwarded, never persisted.
- No credential echo. Startup logs print the auth mode, never the token; tool errors never contain credentials.
PoP for completeness
Where the license wire is concerned (SDK ↔ backend, not MCP): gated calls carry Authorization: Entitlement <jws> + DPoP: <proof-jws> where the proof binds htu/htm/iat/jti/h/jwk. Details: Activation and the contract matrix.