OAuth & Scopes
OAuth 2.1 with PKCE-S256 and Dynamic Client Registration (RFC 7591) for AI clients. API-key auth for SDKs and machine-to-machine. Most MCP-aware clients negotiate the OAuth flow automatically — the curl walkthrough below is for clients that don't.
| Use case | Auth | Why |
|---|---|---|
| Claude Desktop / claude.ai / Claude Code | OAuth 2.1 + DCR | Per-user identity, scope challenges, refresh tokens |
| Python SDK, scripts, BI tools, cron jobs | API key | No browser, no user, scoped to one organization |
Discovery
The discovery endpoint advertises every capability — paste the URL into your client and it does the rest:
https://{tenant}.cognethics.com/.well-known/oauth-authorization-serverAuthorization-server metadata
Live response from the gtm tenant (your tenant returns the same shape with its own URLs):
{
"issuer": "https://gtm.cognethics.com",
"authorization_endpoint": "https://gtm.cognethics.com/api/mcp/oauth/authorize/",
"token_endpoint": "https://gtm.cognethics.com/api/mcp/oauth/token/",
"revocation_endpoint": "https://gtm.cognethics.com/api/mcp/oauth/revoke/",
"registration_endpoint": "https://gtm.cognethics.com/api/mcp/oauth/register/",
"jwks_uri": "https://gtm.cognethics.com/.well-known/jwks.json",
"response_types_supported": [
"code"
],
"grant_types_supported": [
"authorization_code",
"refresh_token"
],
"code_challenge_methods_supported": [
"S256"
],
"token_endpoint_auth_methods_supported": [
"none",
"client_secret_post"
],
"scopes_supported": [
"mcp:read",
"mcp:write",
"mcp:execute",
"spare_parts.view",
"spare_parts.add",
"spare_parts.change",
"spare_parts.delete"
],
"response_modes_supported": [
"query"
],
"authorization_response_iss_parameter_supported": true,
"mcp_version": "2025-03-26",
"service_documentation": "https://gtm.cognethics.com/docs",
"mcp_sse_endpoint": "https://gtm.cognethics.com/api/mcp/sse"
}Protected-resource metadata (RFC 9728)
{
"resource": "https://gtm.cognethics.com",
"authorization_servers": [
"https://gtm.cognethics.com"
],
"scopes_supported": [
"mcp:read",
"mcp:write",
"mcp:execute"
],
"bearer_methods_supported": [
"header"
],
"resource_signing_alg_values_supported": [
"RS256",
"HS256"
],
"resource_documentation": "https://gtm.cognethics.com/docs",
"authentication_methods_supported": [
"oauth2"
],
"mcp_version": "2025-03-26",
"platform_support": [
"claude.ai",
"claude-desktop",
"claude-code"
],
"mcp_sse_endpoint": "https://gtm.cognethics.com/api/mcp/sse"
}Scopes
Cognethics advertises three platform-level scopes plus per-app permission scopes granted on-demand via Dynamic Client Registration.
Platform-level scopes
| Scope | Grants |
|---|---|
mcp:read | Read-only access to all MCP tools your user account can see (list, read, search, report queries). |
mcp:write | Create and update operations through MCP tools (entity_crud writes). |
mcp:execute | Workflow actions, smart actions, agent commands, notification sends — full action access. |
Per-app permission scopes
Per-model Django permissions are exposed as scopes following the pattern <app>.<verb>_<model> — e.g. spare_parts.view_workorder, finance.add_invoice.
Currently advertised in scopes_supported: 4 per-app scopes (including spare_parts.view</code>, <code>spare_parts.add</code>, <code>spare_parts.change, …). The full per-model catalog (thousands of entries) is granted on-demand via DCR.
Manual OAuth flow
For clients that don't speak Dynamic Client Registration, register once by hand and run the standard authorization-code + PKCE dance. Three curl calls:
Step 1 — Register a client
curl -X POST 'https://{tenant}.cognethics.com/api/mcp/oauth/register/' \
-H 'Content-Type: application/json' \
-d '{
"client_name": "My App",
"redirect_uris": ["http://localhost:8080/callback"]
}'Step 2 — Authorize the user
# Open this URL in a browser:
https://{tenant}.cognethics.com/api/mcp/oauth/authorize/
?response_type=code
&client_id=<from-register-step>
&redirect_uri=http://localhost:8080/callback
&code_challenge=<base64url-sha256-of-verifier>
&code_challenge_method=S256
&scope=mcp:read
&state=<random-string>The user authorizes in their browser. Cognethics redirects back to your redirect_uri with an authorization code. For headless / desktop clients, use the Out-Of-Band flow by setting redirect_uri=urn:ietf:wg:oauth:2.0:oob — Cognethics will display the code on a web page for the user to copy.
Step 3 — Exchange code for token
curl -X POST 'https://{tenant}.cognethics.com/api/mcp/oauth/token/' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=authorization_code' \
-d 'code=<from-authorize-callback>' \
-d 'code_verifier=<original-verifier>' \
-d 'client_id=<from-register-step>'Returns a JWT access token (validate against /.well-known/jwks.json) and a refresh token. Use Authorization: Bearer <access-token> on every request to /api/mcp/sse.
API keys (for SDKs and machine-to-machine)
For Python SDK use, scripts, cron jobs, and BI tools, Cognethics supports simpler API-key auth alongside OAuth. Keys are bound to one organization at creation time — to call across orgs, mint one key per org.
Send the key as a Bearer token:
curl -H "Authorization: Bearer mcp_..." \
https://{tenant}.cognethics.com/api/mcp/sseMint a key (Django shell on the platform host):
from cognethics.core.models import User, Organization
from cognethics.mcp.models import MCPApiKey
u = User.objects.get(email='[email protected]')
org = Organization.objects.get(id='<your-org-uuid>')
key, plain = MCPApiKey.create_key(
user=u, organization=org,
name='my-integration',
scope='mcp:read mcp:write mcp:execute',
expires_in_days=90,
created_by=u,
)
print(plain) # the only time the plaintext is visibleA REST endpoint exists at POST /api/mcp/api-keys/register/ (rate-limited 5/min). X-Organization-Context is ignored for API-key auth — keys are bound to a single org. For cross-org dispatch, use OAuth.
Revocation
curl -X POST 'https://{tenant}.cognethics.com/api/mcp/oauth/revoke/' \
-d 'token=<access-or-refresh-token>'Next: try the quickstart or browse the handler catalog.