Cadence
Reference

OAuth

Connect an MCP or API client with the OAuth 2.0 authorization server.

Cadence is an OAuth 2.0 authorization server. A client that drives the API or the MCP endpoint on your behalf obtains an mcoa_ access token through the flow below, rather than carrying an API token you minted by hand.

Every client is a public client using PKCE with the S256 method — there is no client secret. The only scope is mcp.

Replace https://cadence.example.com with the address of your Cadence instance.

Discovery

A client finds the endpoints from two discovery documents.

GET /.well-known/oauth-authorization-server returns the authorization-server metadata:

{
  "issuer": "https://cadence.example.com",
  "authorization_endpoint": "https://cadence.example.com/oauth/authorize",
  "token_endpoint": "https://cadence.example.com/oauth/token",
  "registration_endpoint": "https://cadence.example.com/oauth/register",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"],
  "scopes_supported": ["mcp"]
}

GET /.well-known/oauth-protected-resource names the protected resource and the server that guards it:

{
  "resource": "https://cadence.example.com/mcp",
  "authorization_servers": ["https://cadence.example.com"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["mcp"]
}

A 401 from the API or MCP points here through its WWW-Authenticate header, so a client can discover where to authenticate. See Authentication.

Register a client

POST /oauth/register registers a client dynamically. Send client_name, redirect_uris, and optionally logo_uri:

{
  "client_name": "My integration",
  "redirect_uris": ["https://myapp.example.com/callback"]
}

A successful registration returns 201:

{
  "client_id": "…",
  "client_id_issued_at": 1717171717,
  "client_name": "My integration",
  "redirect_uris": ["https://myapp.example.com/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code"],
  "response_types": ["code"]
}

Invalid metadata is refused with 400 and { "error": "invalid_client_metadata", "error_description": "…" }.

Registration is rate-limited per source address: too many registrations from one address in a short window are refused with 429.

Send the operator's browser to GET /oauth/authorize with client_id, redirect_uri, response_type=code, scope, state, code_challenge, and code_challenge_method=S256. PKCE is required — an authorize request without a code challenge is refused.

If the operator is signed out, they are sent to sign in first, then returned to the consent screen. When they approve, Cadence redirects to your redirect_uri with a code and the state you sent. If they decline, it redirects with error=access_denied.

Exchange the code for a token

POST /oauth/token with grant_type=authorization_code, the code, the matching redirect_uri, your client_id, and the code_verifier for your PKCE challenge:

{
  "access_token": "mcoa_…",
  "refresh_token": "mcor_…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "mcp"
}

Refresh with grant_type=refresh_token and your refresh_token at the same endpoint; each refresh rotates the refresh token.

The token endpoint refuses with 400 and one of these error codes:

  • invalid_client — the client is unknown.
  • unsupported_grant_type — the grant_type is not one this server issues.
  • invalid_grant — everything else the exchange rejects: a bad or expired code, a PKCE verifier that does not match, or a replayed or expired refresh token.

Revoke a token

POST /oauth/revoke with the token (an mcoa_ access token or an mcor_ refresh token) and your client_id revokes the whole grant — its access and refresh tokens all stop working. Per the revocation standard, this endpoint always returns 200, whether or not the token was known, so it reveals nothing about a token's validity.

An operator can also disconnect a client from the web interface; see connected applications.

Sign in with Google

An operator signs in to the web interface with Google at GET /auth/google, which returns through GET /auth/google/callback. Signing in with Google links to an existing operator account; it does not create one.

On this page