Authentication
MangroveAI supports multiple authentication methods to accommodate different use cases.
Authentication Methods
| Method | Best For | Flow |
|---|
| Firebase OAuth | Web apps, mobile apps | Firebase SSO -> Exchange for JWT -> Use JWT |
| API Keys | Scripts, server-to-server, agents | Generate key via portal -> Use in Authorization header |
| GCP IAM Tokens | Cloud infrastructure | gcloud auth print-identity-token -> Use in header |
Firebase Authentication (Recommended for Web/Mobile)
Step 1: Client-Side Firebase Authentication
import { initializeApp } from 'firebase/app';
import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "your-project.firebaseapp.com",
projectId: "your-firebase-project"
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);
const firebaseToken = await result.user.getIdToken();
Step 2: Exchange for MangroveAI JWT
curl -X POST https://api.mangrovedeveloper.ai/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"firebase_token": "YOUR_FIREBASE_TOKEN"
}'
Response:
{
"success": true,
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
"user": {
"id": "uuid",
"name": "John Doe",
"email": "john@example.com",
"org_id": "uuid"
}
}
Token Lifetimes:
- Access token: 1 hour
- Refresh token: 30 days
Step 3: Use JWT for API Requests
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
https://api.mangrovedeveloper.ai/api/v1/signals
API Key Authentication (Recommended for Programmatic Access)
Generate an API Key
Requires an active JWT session first:
curl -X POST https://api.mangrovedeveloper.ai/api/v1/auth/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Server Key",
"scopes": ["strategy:read", "strategy:create", "backtest:create"],
"expires_days": 365
}'
Response:
{
"success": true,
"key": "dev_a1b2c3d4e5f6...",
"key_id": "uuid-here",
"key_prefix": "dev_a1b2c3d4",
"name": "Production Server Key",
"created_at": "2025-12-01T10:00:00Z",
"expires_at": "2026-12-01T10:00:00Z"
}
Save the key value immediately. It is only shown once and cannot be retrieved later.
Use the API Key
curl -H "Authorization: Bearer dev_a1b2c3d4e5f6..." \
https://api.mangrovedeveloper.ai/api/v1/signals
Token Refresh
When your access token expires, use the refresh token to obtain a new one:
curl -X POST https://api.mangrovedeveloper.ai/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "YOUR_REFRESH_TOKEN"
}'
API Endpoints
| Method | Endpoint | Description |
|---|
POST | /api/v1/auth/login | Exchange Firebase token for JWT |
POST | /api/v1/auth/refresh | Refresh access token |
GET | /api/v1/auth/profile | Get current user profile |
PUT | /api/v1/auth/profile | Update user profile |
POST | /api/v1/auth/api-keys | Generate new API key |
GET | /api/v1/auth/api-keys | List all API keys |
DELETE | /api/v1/auth/api-keys/{key_id} | Revoke an API key |
Authorization Levels
| Level | Required | Access |
|---|
| Authenticated User | Valid JWT or API key | Own data (strategies, backtests, conversations) within your tier limits |
| Unauthenticated | None | Health checks, Swagger docs, the x402-gated wallet-paid surface (no signup) |
API Key Scopes
Every authenticated endpoint requires a specific scope. When you mint a key with
a non-empty scopes array, each request is checked against that list and a
missing scope returns 403 INSUFFICIENT_PERMISSIONS with the exact scope it
needed (for example, API key does not have scope: strategy:update_status).
Two rules govern what a key can actually do:
- Empty
scopes: [] means full role-based access — the key inherits every
scope its organization role permits. Pass an explicit list only to restrict a
key below its role.
- Scopes are baked at mint time and your role gates them. A
viewer role
only ever gets the read scopes below, regardless of what you request; to write
you need a member (or higher) key. Changing a role later does not re-scope an
already-minted key — revoke and re-mint.
Scope strings use the resource:action form (note: strategy:read, not
read:strategies). Required scope by endpoint:
| Endpoint | Method | Required scope |
|---|
/api/v1/strategies | POST | strategy:create |
/api/v1/strategies, /api/v1/strategies/{id} | GET | strategy:read |
/api/v1/strategies/{id} (update, incl. execution_config) | PUT | strategy:update_status |
/api/v1/strategies/{id}/status | PATCH | strategy:update_status |
/api/v1/strategies/{id}/execution-state | PATCH | strategy:update_status |
/api/v1/strategies/{id} | DELETE | strategy:delete |
/api/v1/execution/evaluate/{id}, /evaluate, /evaluate/bulk | POST | strategy:read |
/api/v1/execution/portfolio | GET | strategy:read |
/api/v1/execution/accounts, /positions, /trades | GET | position:read |
/api/v1/execution/accounts | POST | position:create |
/api/v1/backtesting/backtest, /backtest/bulk | POST | backtest:create |
/api/v1/backtesting/backtest/{id} | GET | backtest:read |
/api/v1/signals/... | GET | signal:read |
/api/v1/signals/evaluate | POST | signal:evaluate |
/api/v1/oracle/backtest/... | POST | oracle:backtest |
/api/v1/oracle/experiments/... | POST | oracle:sweep |
/api/v1/oracle/data/query | POST | data:query |
Updating a strategy’s execution_config (a PUT /strategies/{id}) requires the
strategy:update_status scope — the same scope that guards status changes. A
read-only (viewer) key cannot perform it. If you only need to evaluate a saved
strategy, strategy:read is sufficient.
Error Responses
401 Unauthorized — Token missing, invalid, or expired. The response carries
a hint with the expected header format and a docs link so the failure is
self-explanatory:
{
"error": "Unauthorized",
"message": "Invalid or expired token",
"hint": "Include 'Authorization: Bearer <API_KEY>' in the request header",
"docs": "https://docs.mangrovedeveloper.ai/authentication"
}
A request sent with no credentials returns the same shape with
"message": "Missing or invalid authentication token".
403 Forbidden — Insufficient permissions. The code is
INSUFFICIENT_PERMISSIONS and the message names the exact scope (or role
permission) that was missing, so you know which scope to add when re-minting the
key (see API Key Scopes):
{
"error": "authorization_error",
"message": "API key does not have scope: strategy:update_status",
"code": "INSUFFICIENT_PERMISSIONS"
}
Security Best Practices
- Never commit tokens or API keys to version control
- Use environment variables for API keys in production
- Rotate API keys regularly — generate new keys, revoke old ones
- Use minimal scopes — only request the permissions you need
- Set expiration dates on API keys
- Store access tokens in memory (not localStorage) for frontend apps
- Store refresh tokens in httpOnly secure cookies or secure storage