API Reference
Authentication
Authentication
This guide covers all authentication methods for accessing the HIVE Protocol API, including session-based auth, bearer tokens, and API key management.
Overview
┌─────────────────────────────────────────────────────────────────┐
│ HIVE Protocol Authentication │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Authentication Methods: │
│ │
│ 1. Session Auth (Browser) │
│ └─ Supabase Auth with automatic token management │
│ │
│ 2. Bearer Token (API) │
│ └─ JWT access tokens from Supabase session │
│ │
│ 3. API Key + Secret (Server-to-Server) │
│ └─ Service role key for backend integrations │
│ │
│ Security Features: │
│ - Row Level Security (RLS) on all tables │
│ - JWT verification on edge functions │
│ - Automatic token refresh │
│ - Rate limiting per user/IP │
│ │
└─────────────────────────────────────────────────────────────────┘Session Authentication
For browser-based applications using Supabase Auth.
Client Setup
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);Sign Up
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'securepassword123',
options: {
data: {
full_name: 'John Doe',
}
}
});
if (error) {
console.error('Sign up error:', error.message);
} else {
console.log('User created:', data.user?.id);
}Response:
{
"data": {
"user": {
"id": "uuid-here",
"email": "user@example.com",
"created_at": "2024-01-15T10:00:00Z"
},
"session": null
},
"error": null
}Sign In
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'securepassword123'
});
if (error) {
console.error('Sign in error:', error.message);
} else {
console.log('Signed in:', data.session?.access_token);
}Response:
{
"data": {
"user": {
"id": "uuid-here",
"email": "user@example.com",
"user_metadata": { "full_name": "John Doe" }
},
"session": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "refresh-token-here",
"expires_in": 3600,
"expires_at": 1705320000
}
},
"error": null
}Sign Out
const { error } = await supabase.auth.signOut();Get Current Session
const { data: { session }, error } = await supabase.auth.getSession();
if (session) {
console.log('Access token:', session.access_token);
console.log('Expires at:', new Date(session.expires_at! * 1000));
}Listen for Auth Changes
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
switch (event) {
case 'SIGNED_IN':
console.log('User signed in:', session?.user.email);
break;
case 'SIGNED_OUT':
console.log('User signed out');
break;
case 'TOKEN_REFRESHED':
console.log('Token refreshed');
break;
case 'USER_UPDATED':
console.log('User updated:', session?.user);
break;
}
}
);
// Cleanup when done
subscription.unsubscribe();Bearer Token Authentication
For API requests from any client.
Getting Access Tokens
const { data: { session } } = await supabase.auth.getSession();
const accessToken = session?.access_token;Making Authenticated Requests
To Database (via Supabase Client):
// Client automatically includes auth headers
const { data, error } = await supabase
.from('agents')
.select('*');To Edge Functions:
const response = await fetch(
`${process.env.NEXT_PUBLIC_SUPABASE_URL}/functions/v1/agent-respond`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'apikey': process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
},
body: JSON.stringify({
swarm_id: 'swm_123',
message: 'Hello!'
})
}
);Using cURL:
curl -X POST \
'https://your-project.supabase.co/functions/v1/agent-respond' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-H 'apikey: YOUR_ANON_KEY' \
-d '{"swarm_id": "swm_123", "message": "Hello!"}'Token Refresh
Access tokens expire after 1 hour. Supabase handles refresh automatically:
// Automatic refresh is handled by the client
// Manual refresh if needed:
const { data, error } = await supabase.auth.refreshSession();
if (data.session) {
console.log('New access token:', data.session.access_token);
}Service Role Authentication
For server-to-server integrations with elevated privileges.
Setup
import { createClient } from '@supabase/supabase-js';
const supabaseAdmin = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: {
autoRefreshToken: false,
persistSession: false
}
}
);Usage
// Service role bypasses RLS - use carefully!
const { data, error } = await supabaseAdmin
.from('profiles')
.select('*')
.eq('id', userId);Required Headers
For Database Requests
| Header | Value | Required |
|---|---|---|
| apikey | Your anon key | Yes |
| Authorization | Bearer {access_token} | Yes |
| Content-Type | application/json | For POST/PATCH |
For Edge Functions
| Header | Value | Required |
|---|---|---|
| Authorization | Bearer {access_token} | Yes |
| Content-Type | application/json | Yes |
| apikey | Your anon key | Yes |
Example with All Headers
const headers = {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'apikey': process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
'X-Client-Info': 'hive-protocol/1.0'
};Error Responses
401 Unauthorized
{
"error": "Invalid authentication credentials",
"code": "UNAUTHORIZED",
"message": "JWT expired or invalid"
}Common Causes:
- Missing Authorization header
- Expired access token
- Malformed JWT
- Invalid signature
Solution:
// Refresh the session and retry
const { data, error } = await supabase.auth.refreshSession();
if (data.session) {
// Retry request with new token
}403 Forbidden
{
"error": "Access denied",
"code": "FORBIDDEN",
"message": "User does not have permission to access this resource"
}Common Causes:
- RLS policy blocking access
- Resource belongs to another user
- Insufficient role/permissions
429 Too Many Requests
{
"error": "Rate limit exceeded",
"code": "RATE_LIMITED",
"retry_after": 60
}Solution:
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
// Retry request
}Rate Limiting
HIVE Protocol implements rate limiting to ensure fair usage:
| Resource | Limit | Window |
|---|---|---|
| API requests | 100 | per minute |
| Auth attempts | 10 | per minute |
| AI responses | 30 | per minute |
| Tool executions | 50 | per minute |
| Webhook sends | 100 | per minute |
Rate Limit Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705320060Handling Rate Limits
async function makeRequestWithRetry(url: string, options: RequestInit) {
const maxRetries = 3;
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(
response.headers.get('Retry-After') || '60'
);
console.log(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}Row Level Security (RLS)
All tables are protected by RLS policies. Users can only access:
- Their own profile and settings
- Agents they created
- Swarms they own or are members of
- Messages in accessible swarms
- Tools they have permission to use
Example RLS Policy
-- Users can only see their own agents
CREATE POLICY "Users can view own agents"
ON agents FOR SELECT
TO authenticated
USING (auth.uid() = user_id);
-- Users can only modify their own agents
CREATE POLICY "Users can update own agents"
ON agents FOR UPDATE
TO authenticated
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);Security Best Practices
1. Never Expose Service Keys
// NEVER do this in client code
const supabase = createClient(url, 'service_role_key'); // WRONG!
// Use anon key for client-side
const supabase = createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY);2. Validate Tokens Server-Side
// In your API route or edge function
const authHeader = request.headers.get('Authorization');
const token = authHeader?.replace('Bearer ', '');
const { data: { user }, error } = await supabase.auth.getUser(token);
if (error || !user) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}3. Use HTTPS Only
All API requests must use HTTPS. HTTP requests will be rejected.
4. Handle Token Expiry Gracefully
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'TOKEN_REFRESHED') {
// Update any cached tokens
updateStoredToken(session?.access_token);
}
if (event === 'SIGNED_OUT') {
// Clear sensitive data and redirect
clearUserData();
router.push('/login');
}
});5. Implement Request Signing (Optional)
For sensitive operations, sign requests:
import crypto from 'crypto';
function signRequest(payload: string, secret: string): string {
return crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
}
const signature = signRequest(JSON.stringify(body), userSecret);
headers['X-Request-Signature'] = signature;Related Documentation
- [Agents API](/docs/api/agents-api): Agent CRUD operations
- [Swarms API](/docs/api/swarms-api): Swarm management
- [Messages API](/docs/api/messages-api): Messaging endpoints
- [Rate Limiting](/docs/advanced/rate-limiting): Rate limit details