HIVE

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

HeaderValueRequired
apikeyYour anon keyYes
AuthorizationBearer {access_token}Yes
Content-Typeapplication/jsonFor POST/PATCH

For Edge Functions

HeaderValueRequired
AuthorizationBearer {access_token}Yes
Content-Typeapplication/jsonYes
apikeyYour anon keyYes

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:

ResourceLimitWindow
API requests100per minute
Auth attempts10per minute
AI responses30per minute
Tool executions50per minute
Webhook sends100per minute

Rate Limit Headers

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705320060

Handling 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;
  • [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