OAuth for MCP clients
AI assistants such as the Claude.ai and ChatGPT connectors cannot take a pasted key. They connect to a project’s MCP server with OAuth 2.1: the person signs in to Spatibase, sees a consent screen and chooses what the assistant may do. This page is for developers building or debugging an MCP client. People who just want to connect an assistant should read Connect an AI assistant.
On this page, $PROJECT_ID is the project’s UUID, and the MCP URL is https://mcp.spatibase.com/projects/$PROJECT_ID (copy the exact address from the project’s AI agents page, in Connect your assistant).
Which standards does Spatibase follow?
Spatibase is its own authorization server and follows the MCP authorization specification, revision 2026-07-28. That includes OAuth 2.1 with PKCE, Protected Resource Metadata (RFC 9728), Authorization Server Metadata (RFC 8414), Resource Indicators (RFC 8707), the iss authorization response parameter (RFC 9207), Client ID Metadata Documents, Dynamic Client Registration (RFC 7591) for older clients, and Token Revocation (RFC 7009).
Clients that can send a header (Claude Code, Cursor, your own agent) can use an API key instead. See MCP server.
How does a client connect?
A client goes through these steps:
-
Call the MCP URL without a token. On a private project the answer is
401withWWW-Authenticate: Bearer resource_metadata="…". On a public project an anonymous call succeeds with read access, so a client that wants more must start the flow itself. -
Read the protected resource metadata at
GET https://mcp.spatibase.com/.well-known/oauth-protected-resource/projects/$PROJECT_ID. It returnsresource(the project’s canonical MCP URL),authorization_servers,scopes_supportedandbearer_methods_supported: ["header"]. -
Read the authorization server metadata at
GET https://api.spatibase.com/.well-known/oauth-authorization-server. It lists the endpoints,code_challenge_methods_supported: ["S256"],client_id_metadata_document_supported: trueandauthorization_response_iss_parameter_supported: true. -
Get a client id, in one of two ways (see the next section).
-
Send the person’s browser to the authorization endpoint:
httpGET /oauth/authorize?response_type=code&client_id=…&redirect_uri=…&code_challenge=…&code_challenge_method=S256&state=…&scope=read%20edit&resource=<MCP URL>Spatibase asks the person to sign in if needed, then shows the consent screen. The request stays valid for 30 minutes, long enough to sign in by email link.
-
The person selects Allow or Cancel. The browser returns to
redirect_uriwithcode,stateandiss, or witherror=access_denied. -
Exchange the code with a form-encoded
POST /oauth/token:httpPOST /oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=…&code_verifier=…&redirect_uri=…&client_id=…&resource=…The answer is
{access_token: "sb_oat_…", token_type: "Bearer", expires_in: 3600, refresh_token: "sb_ort_…", scope}. -
Call the MCP URL with
Authorization: Bearer sb_oat_…. Before the hour is up, refresh withgrant_type=refresh_token&refresh_token=…&client_id=….
How does a client get a client id?
Spatibase accepts two kinds of client id:
- Client ID Metadata Document (preferred). The client id is an
https://URL with a path, on the default port, that serves JSON withclient_id(exactly that URL),client_name,redirect_urisandtoken_endpoint_auth_method: "none". Spatibase fetches it when a person starts connecting: public addresses only, no redirects, one 5-second deadline, at most 10 KB. It is cached according to itsCache-Control, between 5 minutes and 24 hours. - Dynamic client registration.
POST /oauth/registerwith{client_name, redirect_uris, token_endpoint_auth_method?}answers201with{client_id: "sb_client_…", …}. The defaultnonecreates a public client.client_secret_postorclient_secret_basicalso returns aclient_secret(sb_ocs_…), once.
What does the person see on the consent screen?
The consent screen, Connect an app to Spatibase, shows the app’s name, the project and What may it do?. For a client with a metadata document, it shows the domain the app is published from; otherwise it says Spatibase cannot confirm who made the app, and a client registered through /oauth/register carries an unverified badge. If the redirect goes to the person’s own computer, it warns them to allow it only if they started connecting themselves.
| Scope | Label on the consent screen | Pre-selected |
|---|---|---|
read |
Read the project | Always included |
edit |
Edit drafts | Yes |
publish |
Publish | No |
delete |
Delete | No |
model |
Change the content model | No |
The person’s role caps the scope. An owner may allow all five, an editor read edit publish delete, a developer read only. The screen lists only the scopes the app asked for, and greys out those the role does not allow (“not available: your role is …”). Approving more than the role allows answers 422. Each token is also cut to the person’s current role on every request, so changing someone’s role narrows their assistants at once. What each scope unlocks is in the tool list.
Rules worth knowing
| Topic | Rule |
|---|---|
| Redirect URIs | Matched exactly against the registered ones. https, or http only on localhost, 127.0.0.1 and [::1]. No fragments. |
| Errors before a redirect | An unknown client, an unregistered redirect URI, a wrong response_type or missing PKCE show an error page and never redirect. invalid_target and invalid_scope go back to the app only once someone has connected it; before that they are an error page too. |
| PKCE | Required, S256 only. |
resource |
Required on /oauth/authorize and must be a project’s MCP URL. Optional on token and refresh requests, but must match when sent. |
| Scopes | read edit publish delete model. No scope asks for all of them. Unknown values (for example offline_access) are ignored. read is implied by any scope and always granted; the person may leave out the others. A refresh may narrow the scope, never widen it. |
| Authorization codes | sb_oac_…, valid 10 minutes, single use. Using a code twice fails and revokes the tokens the first use produced. |
| Access tokens | sb_oat_…, valid 1 hour, for one project’s MCP URL only, and only while the person is still a member of the project. |
| Refresh tokens | sb_ort_…, valid 30 days, rotated on every use. Presenting a used refresh token again closes the whole connection. |
| Revocation | POST /oauth/revoke with token=…&client_id=… always answers 200. Revoking a refresh token also revokes its access tokens. |
| Error format | /oauth/* endpoints answer {error, error_description}. Rate limits per IP answer 429 {error: "rate_limited"} with Retry-After; on /oauth/authorize a 429 page. |
| Storage | Spatibase stores only SHA-256 hashes of codes, tokens and client secrets. |
Connected apps
Every approval creates a connection for one person, one app and one project. Approving the same app for the same project again updates that connection.
People see their connections in the account menu under Connected apps, with the project, the permissions, when it was connected and when it was last used. Disconnect removes access straight away. Connecting, changing and disconnecting are recorded in the project’s Activity, and changes the assistant makes appear there as “person via app”.
Related
Updated