Authentication
API authentication methods and best practices.
Supascale API supports two authentication methods: session-based for web UI and API key-based for programmatic access.
Authentication Methods
| Method | Use Case | How It Works |
|---|---|---|
| Session | Web UI | Automatic via cookies |
| API Key | Programmatic | X-API-Key header |
Session Authentication
Used automatically by the web interface.
How It Works
- User logs in via
/api/auth/signin - Server sets session cookie
- Subsequent requests include cookie automatically
- Sessions managed by NextAuth.js
Session Endpoints
POST /api/auth/signin # Sign in POST /api/auth/signout # Sign out GET /api/auth/session # Get current session
API Key Authentication
For programmatic access from scripts, CI/CD, or integrations.
Request Format
Include the API key in the X-API-Key header:
curl https://supascale.example.com/api/v1/projects \ -H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
API Key Format
sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Prefix:
sk_live_ - 32 alphanumeric characters
Creating API Keys
See API Keys for detailed instructions.
curl -X POST https://supascale.example.com/api/v1/settings/api-keys \
-H "X-API-Key: admin-key" \
-H "Content-Type: application/json" \
-d '{
"name": "My Integration",
"permissions": {
"projects": "write",
"backups": "read",
"tasks": "none",
"cloudStorage": "none",
"system": "none"
},
"allowMcp": false
}'
MCP access
allowMcp controls whether the key may be used by an AI assistant over MCP. It defaults to false, and keys created before MCP shipped remain false after upgrading.
This is separate from the permissions below on purpose: it is a capability of the key, not a resource scope. A key still needs the relevant permission for whatever the assistant asks it to do, and the server's exposed-tool list can restrict it further.
Endpoints reachable with an API key
Not every endpoint accepts API key authentication. Supascale keeps an explicit allowlist of the routes that do; anything not on it requires a logged-in browser session and will redirect an API client to the login page rather than returning JSON.
This is deliberate — a new endpoint has to be registered before a key can reach it, so an endpoint can never become key-accessible by accident. The trade-off is that if you call an endpoint documented elsewhere and receive a redirect instead of JSON, that endpoint is session-only.
Currently reachable with an API key:
| Area | Endpoints |
|---|---|
| Projects | /projects, /projects/:id/analytics, /projects/:id/logs, /projects/:id/domain, /projects/:id/certificate (+ /status, /obtain, /renew, /revoke, /upload), /projects/:id/import/{database,functions,storage} |
| Backups | /backups, /backups/:id, /backups/:id/download, /backups/:id/restore, /backups/:id/restore/stream, /restore-jobs, /restore-jobs/:id |
| Cloud storage | /cloud-storage, /cloud-storage/:id |
| Tasks | /tasks, /tasks/:id, /tasks/:id/run |
| System | /system/logs, /system/resources, /system/resources/history, /system/startup, /system/container-settings |
| MCP | /mcp, /mcp/manifest, /mcp/call |
Endpoints that test cloud storage connections, and the certificate validation step, are session-only: they open outbound connections using caller-supplied details, so they are kept to authenticated browser use.
Settings and account management — API key administration, password changes, 2FA — are always session-only. An API key can never mint another key or alter authentication settings.
Permissions
API keys have granular permissions per resource:
| Permission | Description |
|---|---|
none | No access |
read | GET requests only |
write | All methods (GET, POST, PUT, DELETE) |
Resources
| Resource | Covers |
|---|---|
projects | Project management, containers, domains, certificates |
backups | Backup creation, restoration, listing |
tasks | Scheduled tasks management |
cloudStorage | Cloud storage provider configuration |
system | System resources, logs, updates |
Permission Check
When a request is made:
- Check the endpoint accepts API key authentication (see above)
- Extract API key from header
- Validate key exists and not expired
- Determine required permission for endpoint
- Compare against key's permissions
- Allow or deny with 403
Error Responses
401 Unauthorized
No or invalid authentication:
{
"success": false,
"error": "Unauthorized"
}
Causes:
- Missing
X-API-Keyheader - Invalid API key
- Expired API key
403 Forbidden
Authenticated but insufficient permissions:
{
"success": false,
"error": "Insufficient permissions"
}
Causes:
- API key lacks required permission
- Attempting write operation with read-only key
Rate Limiting
API requests are rate limited to prevent abuse:
| Endpoint Type | Limit |
|---|---|
| General | 100 requests/minute |
| Heavy operations | 10 requests/minute |
Rate limit headers:
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1642089600
When exceeded:
{
"success": false,
"error": "Rate limit exceeded"
}
Status: 429 Too Many Requests
Best Practices
Security
- Use HTTPS only - Never send keys over HTTP
- Rotate keys regularly - Every 90 days recommended
- Minimum permissions - Only grant what's needed
- Set expirations - Limit key lifetime
Implementation
- Store securely - Use environment variables or secrets manager
- Never commit - Keep keys out of version control
- Handle errors - Check for 401/403 responses
- Implement retry - Handle rate limits gracefully
Example: Environment Variable
# .env SUPASCALE_API_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx # Usage curl https://supascale.example.com/api/v1/projects \ -H "X-API-Key: $SUPASCALE_API_KEY"
Example: Error Handling (Node.js)
async function callApi(endpoint) {
const response = await fetch(`https://supascale.example.com${endpoint}`, {
headers: {
'X-API-Key': process.env.SUPASCALE_API_KEY
}
});
if (response.status === 401) {
throw new Error('Invalid or expired API key');
}
if (response.status === 403) {
throw new Error('Insufficient permissions');
}
if (response.status === 429) {
// Wait and retry
await sleep(60000);
return callApi(endpoint);
}
return response.json();
}
Testing Authentication
Verify API Key
# Should return project list if key is valid curl https://supascale.example.com/api/v1/projects \ -H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Check Permissions
# Returns 403 if key lacks projects:write permission
curl -X POST https://supascale.example.com/api/v1/projects \
-H "X-API-Key: read-only-key" \
-H "Content-Type: application/json" \
-d '{"id": "test"}'