Security model
CP-MCP is a thin adapter that holds your Cloudpath admin credentials on your behalf, authenticates every request to a single user, and never exposes secrets to Claude. This page covers the posture in detail.
Two sign-in flows, one identity
Section titled “Two sign-in flows, one identity”Two independent OAuth flows authenticate the two things that reach the server: your browser (to manage credentials) and Claude (to make MCP requests).
- Web dashboard — Google OAuth (Authorization Code + PKCE) issues a session
cookie
cpmcp_session. Only the SHA-256 hash of the cookie is stored. - MCP connector — Claude registers via OAuth 2.1 Dynamic Client
Registration (RFC 7591) + PKCE. The access token (prefix
cpmk_) is stored hashed and bound to your user id; the hash is checked before any Cloudpath call.
Both flows resolve to the same user record, so your connector identity and your dashboard identity are one and the same.
Credentials at rest
Section titled “Credentials at rest”Your Cloudpath password is stored in Cloudflare D1, encrypted with
AES-256-GCM using a per-record key derived via HKDF-SHA256 from a root
ENCRYPTION_KEY that lives only in Cloudflare’s encrypted secret store. The
plaintext password is decrypted in memory only when a new Cloudpath JWT needs to
be minted — it is never returned to Claude, written to a log line, or placed in
any tool response.
The Cloudpath JWT
Section titled “The Cloudpath JWT”Cloudpath authenticates API callers with a short-lived JWT (~5 minute lifetime)
minted by posting your username and password to /token on the relevant
surface root. CP-MCP manages that lifecycle server-side:
- On the first
call, CP-MCP reads a cached JWT from a per-user, per-surface key-value entry (Cloudflare KV,cp_token:<userId>:<surface>). - On a miss, it decrypts your password just long enough to mint a fresh JWT, then caches it — capped at 240 seconds, a safety margin below the upstream’s ~5-minute expiry.
- The JWT is attached to every upstream request as the raw
Authorizationheader — Cloudpath does not accept aBearerprefix. - A
401or406from Cloudpath triggers exactly one automatic re-mint and retry. Repeated auth failures surface to the model asok: false.
Claude never handles the JWT directly.
TLS to Cloudpath
Section titled “TLS to Cloudpath”Cloudflare Workers enforce strict TLS on outbound fetch and do not expose a
skip-verify option, so your Cloudpath deployment must present a publicly
trusted TLS certificate.
- Cloud-hosted Cloudpath at
*.cloudpath.netalready presents a valid certificate — nothing to do. - On-premises installs with a self-signed certificate will not work. Install a certificate from a public CA.
Access control
Section titled “Access control”CP-MCP deliberately does not layer its own role model on top of Cloudpath. Claude can reach any endpoint the saved admin account is permitted to call, for any HTTP method — there is no separate read-only mode or confirm-before-write gate in CP-MCP. Access is governed entirely by the Cloudpath account you save. Use Cloudpath’s role-based access controls to scope that account by role and permission if you want to limit what Claude can do.
Stopping Claude’s access
Section titled “Stopping Claude’s access”To cut Claude off from your Cloudpath — offboarding, responding to a suspected leak, or just pausing while you investigate — delete your saved credentials in the dashboard. The encrypted password is removed from D1, and every subsequent Cloudpath call fails immediately because there is nothing left to mint a JWT from.
One caveat to know: a JWT already cached in KV keeps working until its short TTL (under 5 minutes) expires. For an instant cutover, also rotate the password in Cloudpath itself, which invalidates that cached token upstream right away.
Rotating the password
Section titled “Rotating the password”- Rotate — paste the new password in the dashboard and save. The old ciphertext is replaced, and the next call mints a fresh JWT with the new password. No change is needed in Claude.
- Saving new credentials flushes the cached JWTs, so switching deployments takes effect on the next call.