Security model
The system has three edges. Each has its own credential, and they are never mixed.
| Edge | Who | Credential |
|---|---|---|
| A | Human to dashboard (webmcp.fast) | Emailed 6-digit code, then a session cookie |
| B | Agent harness to endpoint (<handle>.webmcp.fast/<device>/<server>/mcp) | OAuth 2.1 access token, or a connector token |
| C | Daemon to gateway (/connect WebSocket) | Ed25519 device key |
A. The human
The code is 6 digits, stored hashed, valid for 10 minutes, single use, bound to the requesting browser by a pre-auth cookie, burned after 5 wrong attempts and rate limited per email and per IP. The session cookie is HttpOnly, Secure, SameSite=Lax and host-only on the apex, so tenant hostnames never see it.
B. The agent
The apex is an OAuth 2.1 authorization server: RFC 8414 metadata, dynamic client registration (RFC 7591) and Client ID Metadata Documents, PKCE S256, one-hour access tokens and rotating refresh tokens, stored hashed. The client sends the MCP URL as the RFC 8707 resource. The consent screen accepts it only if it names an endpoint on a handle the signed-in user manages. The grant is bound to that one URL. The scope for a relayed endpoint is mcp. The management MCP server on the apex uses the separate scope manage.
Every method, including initialize, answers 401 with a WWW-Authenticate header naming the RFC 9728 protected-resource metadata when the request carries no valid credential. Endpoints never read cookies.
A connector token (wmf_ and 43 characters) is the fallback for a harness that cannot open a sign-in window. It is shown once, stored as a SHA-256 hash, and bound to one handle, one device and one server alias.
C. The daemon
The key pair is generated on the device before pairing, so approval binds to that public key: another machine that learns the pairing code gains nothing. Every connection is authenticated by signing a fresh server challenge. The key file is mode 0600. Revocation closes the socket, and the daemon stops retrying.
Who decides what is exposed
Only the daemon's own config, changed with webmcp attach and webmcp detach on the machine, can add a server. The gateway keeps a policy per device and alias (enabled, disabled, pending, removed) and can only narrow what the device offers.
Limits
1 MB per request, 8 MB per result, 60 seconds per relayed call, JSON-RPC batches refused, sessions idle out after 24 hours. Plan limits are enforced when a device pairs, when a server is advertised and when a connector is granted.
What is recorded
Per relayed call: time, device, server, method, tool name, duration, outcome. No argument or result bodies. Kept 30 days. Relayed traffic is not stored. See privacy and the overview on the security page.