Authentication
There are three kinds of credential and they are deliberately not interchangeable. Which one you hold decides what you can reach, and the wrong one does not get a hint that a better one exists.
Three credentials, three jobs
| Credential | Looks like | Who holds it | Can |
|---|---|---|---|
| Project API key | csk_live_… | Your website, your build step | Read published content in one project. A key made with more access can also write or publish |
| Dashboard session | A short-lived bearer token | A person signed in to the dashboard | Everything their role allows |
| Connected AI tool | Issued by signing in (OAuth); you never see it | Claude, ChatGPT, Cursor or another MCP client | What its owner’s role allows in the workspaces they chose, without deleting unless allowed |
A dashboard session never becomes an external API credential and an API key never reaches the dashboard. They are different products for different consumers that happen to share a request pipeline.
Project API keys
This is the credential you put in your website. It belongs to exactly one project. You choose its access when you create it: read only, read and write drafts, or read, write and publish. See API key access. A key made with Read published posts can only read, and it can only see published content.
The format
csk_live_0G8H2K4M6P9R_xJ3kQ8vN2mR7pL4wT6yB1cF5hD9gS0aZ3eU7iO2nM4
└┬─┘ └┬─┘ └─────┬────┘ └───────────────┬────────────────────────┘
│ │ key id secret, 32 bytes from a CSPRNG
│ └─ environment: live or test
└─ product-neutral prefix- The secret is shown once, at creation. It is stored as a keyed hash and cannot be recovered — if it is lost, create another and revoke the old one.
- Revoking takes effect within five seconds, everywhere, and the row stays in your list marked revoked rather than disappearing.
- The key id is readable aloud: no ambiguous 0/O or 1/I/l, so it survives being quoted to support over the phone.
- A key from one workspace against another workspace’s project is a 404, not a 403. The surface does not confirm what it will not serve.
?status=draft. Treat anything a read-only key can read as public, because it is: it sits in page source. Keep keys that can write on a server.Locking a key to your own sites
A browser may use a project’s key on the website set in the project’s settings, with or without www, and nowhere else until you list more origins in the project’s settings. Server-side requests send no origin and are never restricted.
The check runs on the real request rather than on the preflight, because a preflight carries no Authorization header and therefore cannot know which project’s list to apply. A refused origin gets 403 ORIGIN_NOT_ALLOWED.
Dashboard sessions
People sign in with Google, Apple, a code sent by email or their company’s single sign-on, with two-step sign-in on top if they turn it on. There is no password to choose, to leak, to reset or to reuse from somewhere else. GET /v1/auth/google/start or GET /v1/auth/apple/start sends them to the provider; the callback returns a short-lived access token plus a refresh cookie. The cookie is HttpOnly, SameSite=Strict and scoped to /v1/auth, so no script on the page can read it and no other site can send it.
A session is not scoped to one workspace, so a request has to say which one it means with X-Tenant-Id. That header cannot widen what the session can reach; it only picks from inside it, and naming a workspace you do not belong to is refused at the membership lookup.
Refreshing
# The refresh token rotates on every use. Presenting an old one revokes the
# whole session family -- that is theft detection, not an inconvenience.
curl -X POST https://api.cmskite.com/v1/auth/refresh --cookie-jar jar --cookie jar| Role | Can |
|---|---|
| Owner | Everything, including changing the plan and deleting the workspace |
| Admin | Manage projects, keys, members and see billing — but not change the plan |
| Editor | Write and delete content |
| Viewer | Read content, projects and keys |
Connected AI tools
An AI tool is connected by adding https://api.cmskite.com/mcp to it and signing in. You choose all your workspaces or one, and whether it may delete content; then you press Allow. The tool gets a short-lived credential of its own that it renews by itself, and nobody copies or pastes a secret.
It is gated twice and needs both. What you allowed is one half, and the role is yours, resolved fresh on every request — so somebody demoted to viewer takes the write access of every tool they connected with them on the next call. It does not carry a snapshot of what they could do the day they connected it.
Some things are not on the list at all: changing the plan, deleting a project or deleting the workspace. No connected tool can do those, whatever its owner can do. Disconnect a tool in Settings → Connected apps and its access ends.
Sending a credential
Authorization: Bearer csk_live_0G8H2K4M6P9R_xJ3kQ8vN2mR7pL4wT6yB1cF5hD9gS0aZ3eU7iO2nM4Always the Authorization header — never a query parameter. A credential in a URL is a credential in an access log, in a referrer header and in somebody’s browser history.







