Three kinds of key
What the publishable key, secret key and access token are for, and which one must never be in a browser.
Three kinds of key
get_project_keys gives you all three. They have different uses, and putting one in the wrong place causes incidents.
| Key | Where | What it can do |
|---|---|---|
| Publishable key | Fine in browsers and apps | Only what the access rules allow |
| Secret key | On the server only | Bypasses every access rule |
| Access token (PAT) | This MCP server and the management API | Creates and deletes projects |
Keys per use
The two keys from get_project_keys are tied together, so if one leaks you have to replace both.
To give each server or app its own key, create named keys with create_api_key.
bw_publishable_… has the same rights as the publishable key, bw_secret_… the same as the secret key.
list_api_keys shows when each key was last used, so revoke unused keys one by one with revoke_api_key.
When a key leaks
get_jwt_signing the signing method (HS256 | ES256) and old keys still accepted
rotate_signing_key a new key to sign the publishable and secret keys (grace_hours: 0, 1, 24, 168)
retire_signing_key end an old key's grace period now
set_jwt_signing sign-in tokens as ES256 (other servers verify them with a public key)rotate_signing_key changes both keys from get_project_keys. Every key in your apps has to be moved over, so
after a leak use grace_hours: 0; for a planned rotation, allow as much grace as moving takes. Only owners and admins can do this.
With grace_hours: 0 (or empty), put the project name exactly in confirm.
When you only need values for frontend code, call get_project_keys { ref, only: "publishable" } to get just the address and the publishable key.
Never do this
Never put the secret key in browser code, a mobile app or a public repository. That key reads and writes every table in the project with no rules applied. If a key has to go into frontend code, it is always the publishable key.
Addresses
The project API is at https://<ref>.<zone>. get_project_keys tells you this too.
GET https://<ref>.<zone>/rest/v1/notes?select=* apikey: <publishable key>
POST https://<ref>.<zone>/auth/v1/signup apikey: <publishable key>