Authentication
Auth across the platform — wallet JWT (Dynamic.xyz), scoped API keys, MCP OAuth, session lifetimes.
What this is
TRUE has three auth flows for three different surfaces: wallet-based JWT for end users, scoped API keys for backend integrations, and MCP OAuth for multi-user agentic clients. Pick the one that matches your client; never mix them.
Wallet-based JWT (Dynamic.xyz)
End users authenticate by signing a one-time message with their Solana wallet. The signature is verified by Dynamic.xyz and exchanged for a short-lived JWT bound to the wallet address. The JWT carries the user’s wallet pubkey, locale preference, and feature scopes; it does not carry any custodial signing power.
- JWT lifetime: 1 hour. Refresh runs silently against an opaque refresh token stored in HttpOnly cookies.
- Refresh lifetime: 30 days. After 30 days of inactivity the user re-signs.
- Revocation: instant via the dashboard or
POST /api/v1/auth/revoke.
Scoped API keys
Backend integrations use static keys with explicit scopes:
tp_live_…— production keys.tp_test_…— sandbox keys, no real funds, no real points.
Scopes are granted at issuance time and cannot be expanded later — issue a new key with the wider scope and revoke the old one. Available scopes:
| Scope | Allows |
|---|---|
read:price | TRUE Quotes reads, market data |
read:catalysts | Catalyst feed reads |
read:user | Authenticated user’s profile, watchlist, points |
subscribe:webhooks | Webhook registration & delivery |
read:mcp | MCP read-only tool calls |
execute:mcp | MCP execution tools (gated, partner-tier) |
MCP OAuth
Multi-user MCP clients (AI assistants, research workspaces) use the OAuth 2.1 + PKCE flow. The grant binds the MCP session to a specific TRUE user wallet so each tool call inherits that user’s scopes, watchlist, and points balance.
GET https://app.truefinance.ai/api/v1/oauth/authorize POST https://app.truefinance.ai/api/v1/oauth/token # Authorization URL
https://app.truefinance.ai/api/v1/oauth/authorize
?response_type=code
&client_id=cli_01JX...
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&code_challenge=...
&code_challenge_method=S256
&scope=read:price%20read:user%20read:mcp
&state=opaque
PKCE is mandatory for public clients. Refresh tokens are rotated on every use.
- Never commit keys to repos. Even private repos. Use environment variables or a secrets manager; rotate on a known cadence.
- Never put keys in client-side bundles. Proxy through your backend.
- Use the smallest viable scope set per integration. A key without
execute:mcpcannot trigger execution if it leaks. - On compromise: revoke immediately, then rotate downstream consumers, then audit the key’s usage history.
- Phishing pattern: any “key verification” link asking you to paste a key is a phishing attempt. TRUE never asks for raw key material.
When to use which
- Wallet JWT — your client renders the TRUE app or a thin embed where the user holds the wallet.
- API key — your backend talks to TRUE on behalf of itself (data ingestion, webhooks, monitoring).
- OAuth — your AI assistant talks to TRUE on behalf of an end user via MCP.
Code samples
// TypeScript — using a scoped API key
const r = await fetch('https://quotes.truefinance.ai/v1/price/SOL', {
headers: { Authorization: `Bearer ${process.env.TRUE_API_KEY}` },
});# Python
import os, httpx
r = httpx.get(
"https://quotes.truefinance.ai/v1/price/SOL",
headers={"Authorization": f"Bearer {os.environ['TRUE_API_KEY']}"},
timeout=10.0,
)
r.raise_for_status()// Rust (reqwest)
let token = std::env::var("TRUE_API_KEY")?;
let resp = reqwest::Client::new()
.get("https://quotes.truefinance.ai/v1/price/SOL")
.bearer_auth(token)
.send().await?
.error_for_status()?;Rotation
Quarterly is the recommended cadence. The dashboard supports overlap windows: provision a new key, deploy to consumers, revoke the old key after the rollout completes.
Safety, limits, failure modes
- Key compromise. Revoke first; then rotate; then audit. The dashboard shows last-used IP and tool histogram per key.
- Token replay. JWTs include a
jticlaim and are bound to the wallet pubkey; replays from a different IP/origin trigger a soft revoke. - Clock skew. JWT validation tolerates ±60s of clock skew between issuer and consumer.
- OAuth state mismatch. A returned
statevalue that doesn’t match the request is rejected; treat any mismatch as a CSRF attempt.
See also
- MCP — the surface OAuth grants are scoped against.
- Rate Limits — per-key and per-user quotas.
- Safety Overview — broader key and wallet hygiene.