Authentication
Signing in with OAuth, API keys, and what each site role can do.
Every request to the MCP server is authenticated, initialize and tools/list included. There are two ways in, and both end with the same credential: a Pink API key (cm_live_…) tied to your account.
| Way in | Best for | What you configure |
|---|---|---|
| Sign in (OAuth) | claude.ai, ChatGPT, Claude Desktop, Claude Code, Cursor | Only the server URL. The client signs you in on first use. |
| API key | Scripts, workflow tools, scheduled jobs, clients that can't open a browser | A key you create on the Connect page |
Either way, the key acts as you: it reaches every site you own or are a member of, and it can do anything your role on that site allows. Treat it like a password.
Sign in (OAuth)
Point a client at https://app.edit.pink/api/mcp without a credential and the server answers 401 with a challenge that tells the client where to sign in:
MCP clients that support authorization follow that link, sign you in at app.edit.pink, and ask you to approve the connection once. Pink supports:
| Protected resource metadata | /.well-known/oauth-protected-resource (also at /.well-known/oauth-protected-resource/api/mcp) |
| Authorization server metadata | /.well-known/oauth-authorization-server (also at …/api/mcp) |
| Grants | authorization_code with PKCE (S256), and the device code grant |
| Client registration | Dynamic (/api/oauth/register); public clients, no client secret |
| Scope | mcp |
| Token | A cm_live_… API key, returned as the access_token, sent as Authorization: Bearer … |
The token does not expire on its own. It stops working when you revoke it on the Connect page.
The stdio bridge
The local bridge (@editpink/mcp, which the Claude Desktop .dxt also runs) signs in with a device code. On the first tool call it opens a browser tab at https://app.edit.pink/device with a short code to approve; once you approve, it stores the key in ~/.editpink-mcp-state.json (readable only by you) and retries the call. If you revoke that key later, calls fail with unauthenticated; delete ~/.editpink-mcp-state.json and the bridge signs in again on its next call.
API keys
Create a key on the Connect page (API keys → New key). The full key is shown once; copy it then. The list shows each key's prefix, when it was created and last used, and lets you revoke it. A revoked key stops working at once.
Send it one of three ways:
A key in the URL is a secret in the URL: anyone who sees the URL can use your account. Prefer the header wherever the client allows it.
When the key is wrong
| Situation | Response |
|---|---|
| No credential | 401, {"error":"unauthorized", …}, with the WWW-Authenticate challenge above |
Key unknown, revoked or expired, or not a cm_live_ key | 401, {"error":"invalid_token", …}, and the challenge carries error="invalid_token" |
| Key could not be checked (a passing fault on our side) | 503, {"error":"temporarily_unavailable", …}, with no challenge. Retry with the same key. |
Sites and roles
A key reaches every site your account owns or is a member of. list_sites returns them, each with your role:
| Role | Who | Can |
|---|---|---|
| Owner | The account that created the site | Everything, including members, publishing settings and billing. The site's credit usage is charged to the owner. |
| Manager | Invited member | Manage the site (members, publishing settings) and all content work. Spends the owner's credits. |
| Editor | Invited member | Content work only, not members or publishing settings. Spends the owner's credits. |
Selecting a site you are not a member of fails with site_access_revoked, and one that does not exist with site_not_found. A tool call on a bound site you have since lost access to (or that was deleted) fails with pinned_site_invalid: call list_sites and select again. See Responses and errors.
Keep keys safe
- Use one key per integration, so you can revoke one without breaking the rest.
- Never put a key in client-side code or a public repository.
- If a key leaks, revoke it on the Connect page and create a new one.