Skip to content

Authentication

All RTCstack API endpoints (except GET /v1/health) require two headers on every request.

Headers

HeaderDescription
X-Api-KeyThe API key configured in API_KEY env var
X-RTCstack-TimestampUnix timestamp in seconds (string)
X-RTCstack-SignatureHMAC-SHA256 signature of the request

Signature Construction

The signature is computed over a canonical string:

METHOD\n
PATH\n
TIMESTAMP\n
SHA256(body)

Where:

  • METHOD is uppercase (POST, GET, etc.)
  • PATH is the URL path including query string (e.g. /v1/token)
  • TIMESTAMP is the same value as X-RTCstack-Timestamp
  • SHA256(body) is the hex-encoded SHA-256 hash of the raw request body (empty string for bodyless requests)

The HMAC key is API_SECRET from your .env.

TypeScript Example

ts
import { createHmac, createHash } from 'crypto'

async function signedFetch(url: string, options: RequestInit = {}) {
  const method = (options.method ?? 'GET').toUpperCase()
  const path = new URL(url).pathname + new URL(url).search
  const timestamp = Math.floor(Date.now() / 1000).toString()
  const body = options.body ? String(options.body) : ''
  const bodyHash = createHash('sha256').update(body).digest('hex')

  const canonical = `${method}\n${path}\n${timestamp}\n${bodyHash}`
  const signature = createHmac('sha256', process.env.API_SECRET!)
    .update(canonical)
    .digest('hex')

  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'Content-Type': 'application/json',
      'X-Api-Key': process.env.API_KEY!,
      'X-RTCstack-Timestamp': timestamp,
      'X-RTCstack-Signature': signature,
    },
  })
}

Replay Protection

The API rejects requests with a timestamp more than 5 minutes in the past or future. This prevents replay attacks even if a signature is intercepted.

Error Responses

StatusCause
401Missing or invalid X-Api-Key
401Missing signature headers
403Invalid HMAC signature
403Timestamp outside 5-minute window

Production Checklist

  • Store API_KEY and API_SECRET in your secrets manager (Vault, AWS Secrets Manager, etc.)
  • Never log the full signature header
  • Rotate API_SECRET by updating .env and restarting the API container
  • The SDK never calls the RTCstack API directly — only your backend should