Authentication
The Claw GRC API supports two authentication modes: Firebase JWT tokens for user-context requests (from the web app or your code), and long-lived API keys for service-to-service and agent integrations.
Authentication Modes
| Mode | Use Case | Token Format |
|---|---|---|
| Firebase JWT | Human user sessions from the web dashboard or your own app. Short-lived (1 hour). Auto-refreshed by the SDK. | User sessions |
| API Key | Service accounts, CI/CD pipelines, AI agents, MCP server. Long-lived. Revocable. | Service accounts |
Firebase JWT Flow
When a user signs in via the Claw GRC web app (or your own integration using the Firebase SDK), Firebase issues a short-lived ID token (JWT). This token is included in the Authorization header as a Bearer token.
The API Gateway validates Firebase JWTs using Google's public keys. Validation checks the token's signature, expiry, and audience claim. Upon successful validation:
- The Firebase
uidis resolved to a Claw GRC user ID and org ID - The request is annotated with
X-User-IDandX-Org-IDheaders - The request is forwarded to the appropriate backend service
import { getAuth } from 'firebase/auth';
const auth = getAuth();
const user = auth.currentUser;
if (user) {
// Get the Firebase ID token (auto-refreshes every hour)
const idToken = await user.getIdToken();
const response = await fetch('https://api.clawgrc.com/api/v1/frameworks', {
headers: {
'Authorization': `Bearer ${idToken}`,
'Content-Type': 'application/json',
},
});
const frameworks = await response.json();
}Firebase tokens expire after 1 hour
Firebase JWTs have a 1-hour TTL. Useuser.getIdToken(true) to force a refresh, or rely on the Firebase SDK's automatic refresh mechanism. Don't cache tokens across requests — call getIdToken() before each API call.API Keys
API keys are long-lived credentials for non-human callers — CI/CD pipelines, service accounts, AI agents, and the MCP server. API keys start with cgrc_live_ (production) or cgrc_test_ (test environment).
Generating an API key
- Navigate to Dashboard → Settings → API Keys
- Click Generate New Key
- Enter a descriptive name (e.g., "CI/CD pipeline", "Optimus agent")
- Select the permission scopes
- Optionally set an expiry date (max 1 year; never-expire is available for internal service accounts)
- Copy the key immediately — it won't be shown again
Store API keys securely
API keys are shown only once at creation time. Store them immediately in a secret manager (GCP Secret Manager, AWS Secrets Manager, HashiCorp Vault, or a .env file never committed to git). If you lose a key, revoke it and generate a new one.Using an API key
# API keys are passed in the X-API-Key header
curl https://api.clawgrc.com/api/v1/frameworks -H "X-API-Key: cgrc_live_abc123...xyz"
# The org is derived from the API key itself — no X-Org-ID header needed
# (JWT requests derive the org from the user's Firebase profile)API key permission scopes
| Scope | Description |
|---|---|
| read:compliance | Read frameworks, controls, evidence, policies, risks |
| write:compliance | Create and update controls, upload evidence, manage policies |
| read:security | Read assessments, findings, scan results |
| write:security | Create findings, trigger scans, manage tickets |
| read:agents | View registered agents, trust scores, interaction logs |
| write:agents | Register agents, submit interactions, update capabilities |
| read:reports | View and download generated reports |
| admin | Full read/write access — use only for internal service accounts |
Org Scoping with X-Org-ID
All Claw GRC data is scoped to an organization (org_id). The API enforces multi-tenant isolation at the database level using PostgreSQL Row-Level Security.
For Firebase JWT requests: the org is derived from the user's Firebase custom claims or looked up from the auth_identity_lookup table. The gateway injects org context automatically — you don't need to include it.
For API key requests: the org is derived from the API key itself. Each API key is scoped to a single organization at creation time. No separate X-Org-ID header is needed.
# API key requests — org scoping is derived from the key
curl https://api.clawgrc.com/api/v1/controls -H "X-API-Key: cgrc_live_abc123..."
# JWT requests — org is derived from Firebase claims
curl https://api.clawgrc.com/api/v1/controls -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."Rate Limits
| Plan | Rate Limit | Burst |
|---|---|---|
| Starter | 120 requests/minute per org. Single API key. | 120 req/min |
| Growth | 600 requests/minute per org. Up to 10 API keys. | 600 req/min |
| Scale | 3,000 requests/minute per org. Unlimited API keys. | 3000 req/min |
| Enterprise | Custom rate limits and dedicated infrastructure. | Custom |
Rate limit headers are included in every response:
# Response headers
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 487
X-RateLimit-Reset: 1710420300
Retry-After: 43 # Only present when rate-limited (429 response)Error Codes
| HTTP Status | Error Code | Cause |
|---|---|---|
| 400 Bad Request | VALIDATION_ERROR — Request body failed schema validation | 400 |
| 401 Unauthorized | INVALID_TOKEN — Bearer token is missing, malformed, or expired | 401 |
| 401 Unauthorized | REVOKED_KEY — API key has been revoked | 401 |
| 403 Forbidden | INSUFFICIENT_SCOPE — API key lacks required permission scope | 403 |
| 403 Forbidden | ORG_MISMATCH — X-Org-ID doesn't match the key's authorized org | 403 |
| 404 Not Found | RESOURCE_NOT_FOUND — The requested resource doesn't exist in your org | 404 |
| 429 Too Many Requests | RATE_LIMIT_EXCEEDED — You've exceeded the rate limit. Check Retry-After header. | 429 |
| 500 Internal Error | INTERNAL_ERROR — Unexpected server error. Contact support with request-id. | 500 |
Error response format
{
"error": {
"code": "INSUFFICIENT_SCOPE",
"message": "This API key does not have the required scope: write:compliance",
"request_id": "req_01J8X3...",
"docs_url": "https://clawgrc.com/docs/api/authentication#error-codes"
}
}Include request_id when contacting support
Every API response includes arequest_id in the response body and in the X-Request-ID header. Always include this when reporting API issues — it allows support to trace the exact request in our logs.Development Mode
When the API Gateway is running with ENVIRONMENT=development, all authentication is bypassed. Every request is treated as authenticated with the default dev organization ID (00000000-0000-0000-0000-000000000001) and the owner role.
Never use development mode in production
TheENVIRONMENT=development flag disables all authentication and authorization checks. This is only for local development. Always set ENVIRONMENT=production in deployed environments.