Authentication Guide
Overview
The Flotac REST API supports two authentication methods:
- JWT Bearer Tokens - From Supabase Auth (recommended for user-facing applications)
- API Keys - For server-to-server integrations and automation
All API endpoints require authentication except /health and / (root).
Authentication Methods
1. JWT Bearer Tokens (Supabase Auth)
Obtaining a JWT Token
JWT tokens are obtained through Supabase Auth by authenticating users via email/password, OAuth providers, or magic links.
Sign Up a New User:
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
'https://chwjbbvcqsxxgaytqlix.supabase.co',
'YOUR_ANON_KEY'
);
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'secure_password_123',
options: {
data: {
company_id: 'your-company-uuid', // Required for multi-tenancy
role: 'company_user'
}
}
});
if (data.session) {
const jwt = data.session.access_token;
console.log('JWT Token:', jwt);
}
Sign In an Existing User:
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure_password_123'
});
if (data.session) {
const jwt = data.session.access_token;
// Use this token for API requests
}
Using JWT in API Requests:
const BASE_URL = 'https://chwjbbvcqsxxgaytqlix.supabase.co/functions/v1/api-gateway';
const response = await fetch(`${BASE_URL}/api/v1/customers`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json'
}
});
const result = await response.json();
Token Refresh
JWT tokens expire after 1 hour. Use Supabase's automatic token refresh:
// Automatic refresh (recommended)
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'TOKEN_REFRESHED') {
const newJwt = session.access_token;
// Update your token storage
}
});
// Manual refresh
const { data, error } = await supabase.auth.refreshSession();
if (data.session) {
const newJwt = data.session.access_token;
}
2. API Keys
API keys are intended for server-to-server integrations, automation scripts, and third-party applications.
API Key Format
flotac_api_key_(live|test)_[64_hexadecimal_characters]
Examples:
- Live:
flotac_api_key_live_a1b2c3d4e5f6... - Test:
flotac_api_key_test_x9y8z7w6v5u4...
Using API Keys in Requests
API keys are sent in the Authorization header as Bearer tokens:
curl -X GET "https://chwjbbvcqsxxgaytqlix.supabase.co/functions/v1/api-gateway/api/v1/customers" \
-H "Authorization: Bearer flotac_api_key_live_a1b2c3d4e5f6..." \
-H "Content-Type: application/json"
JavaScript:
const FLOTAC_API_KEY = 'flotac_api_key_live_a1b2c3d4e5f6...';
const BASE_URL = 'https://chwjbbvcqsxxgaytqlix.supabase.co/functions/v1/api-gateway';
const response = await fetch(`${BASE_URL}/api/v1/customers`, {
headers: {
'Authorization': `Bearer ${FLOTAC_API_KEY}`,
'Content-Type': 'application/json'
}
});
Python:
import requests
FLOTAC_API_KEY = 'flotac_api_key_live_a1b2c3d4e5f6...'
BASE_URL = 'https://chwjbbvcqsxxgaytqlix.supabase.co/functions/v1/api-gateway'
response = requests.get(
f'{BASE_URL}/api/v1/customers',
headers={'Authorization': f'Bearer {FLOTAC_API_KEY}'}
)
Multi-Tenant Authentication
Company ID Scoping
All API requests are automatically scoped to a company using company_id:
- JWT Tokens: Extracted from
user_metadata.company_id - API Keys: Extracted from
api_keys.company_idtable
How It Works
Request Flow:
1. Client sends request with JWT/API Key
2. Auth middleware extracts company_id
3. All database queries filter by company_id
4. Response contains only company-scoped data
Security Implications
- No cross-company data leakage: Users can ONLY access data for their company
- No RLS policies: Security enforced at application level
- Mandatory company_id: All requests must have valid company context
Security Best Practices
1. Protect Your Credentials
DO:
- Store API keys in environment variables
- Use
.envfiles (excluded from version control) - Rotate API keys regularly (annually or on compromise)
- Use different keys for development and production
DON'T:
- Hard-code API keys in source code
- Commit keys to version control
- Share keys via email or Slack
- Use production keys in test environments
2. Token Storage
Browser Applications:
- Store JWT in
httpOnlycookies (preferred) - Or use
sessionStorage(cleared on tab close) - Avoid
localStoragefor sensitive tokens
Server Applications:
- Store API keys in environment variables
- Use secrets management (AWS Secrets Manager, HashiCorp Vault)
3. HTTPS Only
All API requests MUST use HTTPS. The API gateway rejects HTTP requests.
4. Rate Limiting
The API implements rate limiting per company_id:
- Default: 100 requests per minute
- Burst: Up to 200 requests allowed
- Exceeded: HTTP 429 with
Retry-Afterheader
Handle Rate Limits:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`Rate limited. Retrying after ${retryAfter}s...`);
await sleep(retryAfter * 1000);
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
Troubleshooting
401 Unauthorized
Possible Causes:
- Missing
Authorizationheader - Invalid or expired JWT token
- Invalid API key
- API key revoked or expired
Solutions:
- Verify header format:
Authorization: Bearer <token> - Refresh JWT token (1-hour expiry)
- Check API key format and hash
- Verify API key is active
403 Forbidden
Possible Causes:
- Missing
company_idin user metadata - API key lacks required permissions
- Attempting to access another company's data
Solutions:
- Ensure user signup includes
company_idin metadata - Check API key permissions in database
- Verify
company_idmatches requested resource
429 Rate Limit Exceeded
Solutions:
- Implement exponential backoff
- Cache responses client-side
- Batch requests where possible
- Contact support for rate limit increase
Next Steps
- Quick Start - Get started in 5 minutes
- API Reference - Complete endpoint documentation
- Integration Examples - Real-world use cases