Authentication
Flashpoint.AI has no API keys. Every request carries a short-lived bearer JWT, and the JWT shape depends on which surface you're calling and who you are.
| Surface | Caller | Auth mechanism |
|---|---|---|
| Chat UI (app.flashpoint.ai) | A human researcher | Auth0 OAuth → Flashpoint.AI RS256 JWT |
MCP server (mcp.flashpoint.ai) | A human via Claude Desktop / Cursor / etc. | OAuth 2.1 redirect to Auth0 → mcp-issued user JWT |
MCP server (mcp.flashpoint.ai) | An autonomous agent | Wallet JWT — EIP-191 signature on a nonce |
All bearers go in a standard Authorization header:
Authorization: Bearer <token>
No cookies, no signed requests, no session state on the server.
Chat UI (humans via Auth0)
The chat UI signs you in through Auth0. The browser handles the redirect dance; you don't write code for this. Auth0 issues an id_token which io exchanges for a Flashpoint.AI user JWT — RS256, 180-day expiry, payload {id, kind: "user", expires}. The JWT goes into localStorage and rides on every WebSocket and REST call from the UI.
You won't typically interact with this token directly. If you're building a custom integration that needs to act as a Flashpoint.AI user (rather than an autonomous agent), use MCP via Claude Desktop instead — it's faster to set up and gives you the same identity binding.
MCP humans (OAuth 2.1 via Claude Desktop)
Claude Desktop and other MCP clients discover and complete a standard OAuth 2.1 flow against the Flashpoint.AI MCP server.
The flow
- Client calls
POST /mcpwith no bearer → server returns401+ aWWW-Authenticate: Bearer resource_metadata=…header. - Client fetches the RFC 9728 protected-resource metadata at
/.well-known/oauth-protected-resourceand the RFC 8414 authorization-server metadata at/.well-known/oauth-authorization-server. - Client posts a Dynamic Client Registration (RFC 7591) request to
/oauth/register, gets back aclient_id. - Client opens the browser to
/oauth/authorize?…&code_challenge=…&code_challenge_method=S256with its registered redirect URI (loopback for CLI clients like Claude Code, a hostedhttps://claude.ai/…orhttps://chatgpt.com/…callback for Desktop / web / ChatGPT). mcp-server 302s to Auth0. - You log in with Auth0 (the same account you'd use in the chat UI). Auth0 302s back to mcp-server's
/oauth/callback. - mcp-server renders an HTML team picker listing every team you belong to. You click one.
- mcp-server mints an HS256 JWT bound to
(user_id, team_id)with a 24-hour expiry, 302s back to the client's loopback callback with a single-use authorization code. - Client posts
/oauth/tokenwith the code + the PKCE verifier; gets back the JWT asaccess_token.
After that, the client uses the JWT on every /mcp request. To switch teams, re-run the connection — the picker shows again.
What you do
Per-client setup instructions (Claude Desktop, Claude.ai web, Claude Code CLI, ChatGPT custom connector) live in Connect from your AI assistant. For all of them the OAuth dance is handled automatically — you just paste the server URL and sign in. See Quickstart for the full first-call walkthrough.
Token shape
The access token is opaque from the client's perspective. For the curious:
{
"iss": "flashpoint-mcp",
"kind": "user",
"user_id": "<uuid>",
"team_id": "<uuid>",
"iat": 1779700000,
"exp": 1779786400
}
24-hour TTL. No refresh token — re-OAuth when it expires.
MCP wallet JWT (autonomous agents)
If you're an autonomous agent without a human in the loop, you authenticate by signing an EIP-191 message with your wallet's private key. mcp-server provisions a Flashpoint.AI user + team for your wallet on first contact (idempotent on the address).
The flow
POST /auth/wallet/challenge→ server returns{nonce, message_to_sign, expires_at}. Themessage_to_signis namespaced (flashpoint-mcp-auth:<nonce>) so a signature for us is not reusable elsewhere.- Sign the message with
personal_sign(EIP-191). POST /auth/wallet/tokenwith{address, nonce, signature}→ server recovers the signer, checks it matchesaddress, consumes the nonce, provisionsusers(kind='agent')+teams(kind='agent')if needed, and returns a 1-hour wallet JWT.- Use the JWT on every
/mcprequest:Authorization: Bearer <token>.
Token shape
{
"iss": "flashpoint-mcp",
"kind": "wallet",
"address": "0x…",
"user_id": "<uuid>",
"team_id": "<uuid>",
"iat": 1779700000,
"exp": 1779703600
}
1-hour TTL. Get a new nonce and re-sign when it expires.
Per-call payment (x402)
Wallet agents pay per tool call in USDC on Base. When you hit a paid tool without an X-PAYMENT header, the server returns 402 with the payment terms — payTo address, asset, amount, network — encoded for the x402 protocol. Pay through the x402 facilitator, retry with the X-PAYMENT header, and the server settles on-chain after a successful tool result.
Two important guarantees:
- Wallet-binding. The on-chain
payeraddress must match the wallet address in your JWT. Paying with one wallet under another wallet's bearer is rejected at the verify step (402). - No charge on failure. If the worker returns an error, we skip settlement — your signature is not redeemed.
Human bearers (Auth0 or OAuth) are not gated by x402 — your subscription covers per-call usage.
Errors
Every auth failure returns one of:
| Status | When |
|---|---|
401 | Bearer missing, malformed, expired, or signature invalid |
403 | Account suspended (rare) |
402 | Wallet agent hit a paid tool without payment (see above) |
See Errors for the canonical error envelope.