Authentication
Three ways to connect, all tied to your account: OAuth sign-in for assistants (claude.ai, ChatGPT…), an API key for code and the REST API, or a secret connector URL as a last resort.
Which method should I use?
| Method | For | Gives access to | Revocation |
|---|---|---|---|
| OAuth sign-in | claude.ai (web, mobile, Cowork), ChatGPT, Claude Code, any compatible remote MCP client | MCP server only (/mcp) | Dashboard → Connected apps, takes effect on the next call |
API key normi_… | REST API, scripts, CI, the STDIO package @normi/mcp-dvf, Cursor | REST API and MCP server | Creating a new key revokes the old one |
| Connector URL | Clients with neither OAuth nor custom headers | MCP server only | Dashboard → Tokens, revocable at any time |
OAuth sign-in (MCP server)
Paste https://mcp.normi.fr/mcp into your client, sign in to Normi, then approve the app. No key to copy. See the Claude and ChatGPT guides.
- First approval: if your account doesn't have an API key yet, a free key (500 credits) is created at that point, after a bot check. An account that already has a key keeps its balance and its plan.
- Rotation: creating a new key in the dashboard doesn't disconnect your apps; they use the new key from the next call.
- Key revoked with no replacement: calls fail with
403 no_active_key. Normi never creates a key behind your back; create one and the app resumes. - Lifetime: the access token expires after one hour and the client renews it by itself. Signing out of normi.fr doesn't disconnect your apps.
- Scope: an OAuth token only works on the MCP server. The REST API
/v1requires an API key.
Claude Code
claude mcp add --transport http normi https://mcp.normi.fr/mcp # then, inside Claude Code: /mcp
For MCP client developers
A call without credentials returns 401 with a WWW-Authenticate header that points to the protected-resource metadata (RFC 9728). That names the authorization server, which supports dynamic client registration (RFC 7591), the authorization code flow with PKCE (S256) and refresh tokens.
$ curl -i -X POST https://mcp.normi.fr/mcp HTTP/2 401 www-authenticate: Bearer resource_metadata="https://mcp.normi.fr/.well-known/oauth-protected-resource/mcp"
API key: accepted headers
| Header | Recommended for | Example |
|---|---|---|
X-API-Key | REST API (preferred) | X-API-Key: normi_abc123 |
Authorization | MCP clients (standard Bearer) | Authorization: Bearer normi_abc123 |
Both headers are accepted by the REST API and the MCP server. For standard REST integrations, use X-API-Key.
Examples
curl "https://mcp.normi.fr/v1/transactions?code_postal=75011" \ -H "X-API-Key: normi_your_token"
# Alternatively — Authorization: Bearer (also accepted by the REST API) curl "https://mcp.normi.fr/v1/transactions?code_postal=75011" \ -H "Authorization: Bearer normi_your_token"
MCP configuration (Claude Desktop)
{
"mcpServers": {
"normi": {
"command": "npx",
"args": ["-y", "@normi/mcp-dvf"],
"env": {
"NORMI_API_KEY": "normi_your_token"
}
}
}
}Token format
Normi tokens have this format:
normi_<base64url(32 random bytes)>
The normi_ prefix makes a Normi token easy to spot in your logs and tells it apart from other secrets.
Token rotation
Creating a new token in the dashboard automatically and atomically revokes all your previous tokens. The credit balance is transferred to the new token — you don't get a new batch of 500 free credits.
- Only one active token per account at any time
- Apps connected with OAuth follow the new token automatically
- Revocation is immediate — in-flight requests with the old token fail with HTTP 401
- All data tied to the token (alerts, portfolio) stays accessible with the new token
Security best practices
- Never commit your token to a Git repository. Use environment variables.
- On the server side, keep the token in an environment variable (e.g.
NORMI_API_KEY). Never expose it in frontend code. - If your token is compromised, create a new one immediately from the dashboard. The old one is revoked instantly.
- Server-side verification uses a constant-time comparison (resistant to timing attacks).