Skip to Content
GuidesAuthentication

Authentication

Korala uses HMAC-SHA256 signature authentication to secure API requests. This provides a secure, stateless authentication mechanism that doesn’t require tokens to be stored or refreshed.

Overview

Every API request must include three headers:

HeaderDescriptionExample
X-API-KeyYour API key IDak_live_abc123
X-TimestampUnix timestamp in seconds1704067200
X-SignatureHMAC-SHA256 signaturea1b2c3d4...

Computing the Signature

The signature is computed by creating an HMAC-SHA256 hash of a specific message format using your API secret.

Message Format

{timestamp}.{METHOD}.{path}.{body}

Where:

  • timestamp - The same Unix timestamp sent in the X-Timestamp header
  • METHOD - The HTTP method in uppercase (GET, POST, PUT, DELETE)
  • path - The request path including query string (e.g., /api/v1/documents?limit=10)
  • body - The request body as a string (empty string for GET requests)

Examples

import crypto from 'crypto'; function signRequest( apiSecret: string, method: string, path: string, body: string = '' ): { timestamp: string; signature: string } { const timestamp = Math.floor(Date.now() / 1000).toString(); const message = `${timestamp}.${method}.${path}.${body}`; const signature = crypto .createHmac('sha256', apiSecret) .update(message) .digest('hex'); return { timestamp, signature }; } // Usage const { timestamp, signature } = signRequest( 'your-api-secret', 'POST', '/api/v1/documents/upload-url', JSON.stringify({ filename: 'contract.pdf', contentType: 'application/pdf' }) );

Making Authenticated Requests

import crypto from 'crypto'; const API_KEY = 'your-api-key-id'; const API_SECRET = 'your-api-secret'; const BASE_URL = 'https://api.korala.ai'; async function apiRequest(method: string, path: string, body?: object) { const bodyString = body ? JSON.stringify(body) : ''; const timestamp = Math.floor(Date.now() / 1000).toString(); const message = `${timestamp}.${method}.${path}.${bodyString}`; const signature = crypto .createHmac('sha256', API_SECRET) .update(message) .digest('hex'); const response = await fetch(`${BASE_URL}${path}`, { method, headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY, 'X-Timestamp': timestamp, 'X-Signature': signature, }, body: bodyString || undefined, }); if (!response.ok) { throw new Error(`API error: ${response.status}`); } return response.json(); } // Usage const documents = await apiRequest('GET', '/api/v1/documents');

Timestamp Validation

Requests with timestamps older than 5 minutes are rejected to prevent replay attacks. Ensure your server’s clock is synchronized with NTP.

Error Responses

StatusErrorDescription
401missing_api_keyX-API-Key header is missing
401missing_timestampX-Timestamp header is missing
401missing_signatureX-Signature header is missing
401invalid_api_keyAPI key not found or inactive
401expired_timestampTimestamp is older than 5 minutes
401invalid_signatureSignature doesn’t match

Security Best Practices

  1. Never expose your API secret - Keep it server-side only
  2. Use environment variables - Don’t hardcode secrets in source code
  3. Rotate keys regularly - Create new keys and deprecate old ones
  4. Use separate keys per environment - Different keys for dev/staging/production
  5. Monitor key usage - Review audit logs for suspicious activity
Last updated on