API keys & OAuth
Two authentication mechanisms, one underlying token model. The Bearer key for scripts and ChatGPT/Gemini; the OAuth 2.1 flow for the native connectors of Claude and Mistral.
01The workspace API key
This is the API key MADATA exposes on every workspace. Format:
mia_ followed by 64 hex characters (256 bits of entropy). It is
stored hashed with SHA-256: the server cannot show it again.
A token carries the identity of a workspace user and a scope. Every call runs as that user.
02Create a key
In MADATA: My profile → Account security → API keys → Create a key. An API key connects an external tool to MADATA without a password or two-factor authentication: treat it as a secret.
Restricted to workspace MADATA administrators. The list of eligible users is offered in the form.
- Name
- Free text: helps you find the key in the list.
- Lifetime
- 1 month, 3 months, 6 months, 1 year, or permanent. Default: 365 days.
- Scope
- Read only (default) or Read and write.
- User
- The workspace user whose permissions the key carries (the workspace owner by default).
The key is shown only once, at creation. Copy it immediately; it will never be readable again.
03Use the key
curl -s https://<workspace>.madata.app/mia/mcp \
-H "Authorization: Bearer mia_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"get_kpi","arguments":{"period":"month"}}}'
The workspace URL is shown next to the key. It always looks like
https://<workspace>.madata.app/mia/mcp.
04Scopes
| Scope | Visible tools |
|---|---|
read_only | Read tools only (kind = read). |
full_access | All tools, read and write. |
custom | Only the tools of an allow-list (configurable on the workspace). |
The scope is further clamped by the user's access mode:
a full_access key held by a "Read only" user cannot write.
05Revoke / delete
From the key list: revoke disables the key without
removing it (the history stays); delete erases it for
good. A revoked key returns 401 on the next call.
06OAuth 2.1 (native connectors)
Claude.ai and Mistral Le Chat do not accept a static key: they connect over OAuth 2.1 with PKCE S256. The MADATA server implements the MCP authorization profile:
| Endpoint | Role |
|---|---|
GET /.well-known/oauth-protected-resource | RFC 9728: resource metadata (resource_name: "Madata", scopes_supported: ["mcp"]). |
GET /.well-known/oauth-authorization-server | RFC 8414: endpoints, grant_types authorization_code + refresh_token, code_challenge_methods_supported: ["S256"]. |
POST /mia/mcp/oauth/register | Dynamic client registration (RFC 7591): returns a client_id mcp_…. |
GET /mia/mcp/oauth/authorize | Branded consent page (Madata ↔ Claude). Workspace sign-in required. |
POST /mia/mcp/oauth/authorize/decision | Issues a single-use authorization code, CSRF-protected. |
POST /mia/mcp/oauth/token | Exchanges authorization_code (PKCE S256 mandatory, plain rejected) or refresh_token. |
The issued access token is a real API key: it shows up
in the workspace key list, revocable the same way. A refresh_token
(mrt_…) allows silent renewal. Reconnecting the same
client_id disables that client's previous key.
For claude.ai,
claude.com, console.anthropic.com,
chatgpt.com, chat.openai.com,
platform.openai.com, the client is re-registered on the fly if
its cached client_id no longer exists server-side (database
re-created). PKCE + admin consent still protect the flow.
The OAuth consent is gated: only a workspace MADATA administrator can authorize a connector.
07Lifecycle & security
- Every call runs with the user's permissions, never more.
- The key is stored hashed: it is never shown again.
- Expiry is checked on every call; an expired key returns
401. - The
mrt_prefix of the refresh token makes it unusable as an access key. - Every
tools/callis logged (see Logging).