Skip to main content

API Keys

RadarOS supports per-request API key overrides so clients can pass their own API keys instead of relying on server-side environment variables. Useful for multi-tenant apps, user-provided keys, and development.

Supported Headers

HeaderProviderUse Case
x-openai-api-keyOpenAIGPT, embeddings
x-google-api-keyGoogleGemini, embeddings
x-anthropic-api-keyAnthropicClaude
x-api-keyGenericFallback when provider-specific key not set

How It Works

  1. Client sends a request with one of the headers (or apiKey in body).
  2. Transport layer extracts the key via extractApiKey().
  3. Key is passed to agent.run(input, { apiKey }) or agent.stream(input, { apiKey }).
  4. The model provider uses the per-request key instead of process.env.*.

REST (Express)

# OpenAI agent
curl -X POST http://localhost:3000/api/agents/assistant/run \
  -H "Content-Type: application/json" \
  -H "x-openai-api-key: sk-..." \
  -d '{"input": "Hello!"}'

# In body (alternative)
curl -X POST http://localhost:3000/api/agents/assistant/run \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello!", "apiKey": "sk-..."}'

Socket.IO

// Via handshake
const socket = io("http://localhost:3000/radaros", {
  auth: { apiKey: "sk-..." },
});

socket.emit("agent.run", {
  name: "assistant",
  input: "Hello",
  // Uses handshake.auth.apiKey if apiKey not in payload
});

// Per-request override
socket.emit("agent.run", {
  name: "assistant",
  input: "Hello",
  apiKey: "sk-...",
});

Provider Matching

The transport layer uses a priority-based matching system:
  1. Provider-specific headers — Highest priority. Matched directly to the provider:
    • x-openai-api-key → used when agent uses an OpenAI model
    • x-google-api-key → used when agent uses a Google/Vertex model
    • x-anthropic-api-key → used when agent uses an Anthropic model
  2. Generic headerx-api-key is used as a fallback when no provider-specific header is found. The transport passes it to whatever provider the agent uses.
  3. Body parameterapiKey in the request body is the final fallback.
This allows a single request to carry keys for multiple providers — useful when an agent uses one provider for the main model and another for embeddings or memory extraction:
// Client sends keys for both OpenAI (main model) and Google (embeddings)
fetch("/api/agents/assistant/run", {
  method: "POST",
  headers: {
    "x-openai-api-key": "sk-...",
    "x-google-api-key": "AIza...",
  },
  body: JSON.stringify({ input: "Hello!" }),
});

Security Notes

HTTPS Required

Always use HTTPS in production. API keys sent over HTTP are visible to network intermediaries.

No Key Logging

Never log request headers or bodies that may contain API keys. Configure your logging middleware to redact sensitive headers.

Key Rotation

Support key rotation by accepting new keys without downtime. Per-request keys make this seamless — clients switch to new keys immediately.

Rate Limiting

Apply rate limiting per API key to prevent abuse in multi-tenant setups.
// Example: Express middleware to strip API keys from logs
app.use((req, res, next) => {
  const sanitized = { ...req.headers };
  delete sanitized["x-openai-api-key"];
  delete sanitized["x-google-api-key"];
  delete sanitized["x-anthropic-api-key"];
  delete sanitized["x-api-key"];
  req.sanitizedHeaders = sanitized;
  next();
});

Swagger UI

When Swagger is enabled, the OpenAPI spec includes security schemes for these headers. Users can click “Authorize” and enter their key; it will be sent with each request.