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

Cookie Preferences

We use cookies to enhance your experience, analyze site traffic, and for marketing purposes. By clicking "Accept All", you consent to our use of cookies. Read our Privacy Policy for more information.