# How the Caveman Proxy Handles API Credentials: Architecture and Security Explained

> Discover how the Caveman proxy secures API credentials using CAVE_API_KEY and forwarding provider-specific keys. Learn about its architecture and security measures.

- Repository: [Julius Brussee/caveman](https://github.com/JuliusBrussee/caveman)
- Tags: architecture
- Published: 2026-09-06

---

**The Caveman proxy uses `CAVE_API_KEY` injected via the `x-cave-api-key` header to authenticate gateway requests, while leaving provider-specific credentials (OpenAI, Anthropic, Vertex, Bedrock) untouched during forwarding.**

The Caveman proxy serves as the secure authentication layer between your applications and upstream LLM providers. Built in Go with a modular provider architecture, it enforces strict separation between **gateway authentication** (controlled by Caveman Cloud) and **provider credentials** (controlled by you or your organization). This design prevents credential leakage while supporting both bring-your-own-key (BYOK) and stored key modes.

## Gateway Authentication with CAVE_API_KEY

The proxy's primary authentication mechanism relies on a single environment variable: **`CAVE_API_KEY`**. This secret confirms that requests originate from an authorized Caveman gateway rather than direct provider access.

### Header Injection Pattern

When the proxy receives a request, it automatically appends the `x-cave-api-key` header containing the gateway secret:

```bash

# Environment setup (never commit this)

export CAVE_API_KEY="cave_sk_live_..."

# The proxy injects this header automatically

curl -X POST "http://localhost:8787/w/myapp/openai/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{"model":"gpt-4","messages":[{"role":"user","content":"Hello"}]}'

# Request as seen by upstream provider includes:

# x-cave-api-key: cave_sk_live_...

# Authorization: Bearer sk-openai-...

```

The [`skills/caveman-setup/SKILL.md`](https://github.com/JuliusBrussee/caveman/blob/main/skills/caveman-setup/SKILL.md) file documents this requirement explicitly: gateway auth uses `x-cave-api-key: CAVE_API_KEY` and callers authenticate via `-H "x-cave-api-key: $CAVE_API_KEY"` without manual header management.

### Go Implementation Structure

In [`proxy/providers/vertex/vertex.go`](https://github.com/JuliusBrussee/caveman/blob/main/proxy/providers/vertex/vertex.go) and analogous provider files, the forwarding logic checks for the environment variable and injects the header before roundtripping:

```go
// Simplified from proxy/provider adapters
func (a *adapter) RoundTrip(req *http.Request) (*http.Response, error) {
    // Inject gateway authentication
    if caveKey := os.Getenv("CAVE_API_KEY"); caveKey != "" {
        req.Header.Set("x-cave-api-key", caveKey)
    }
    // Provider headers preserved as-is
    return a.base.RoundTrip(req)
}

```

The [`proxy/providers/vertex/vertex_test.go`](https://github.com/JuliusBrussee/caveman/blob/main/proxy/providers/vertex/vertex_test.go) file verifies this behavior at lines 168-188, asserting that `x-cave-api-key` appears in upstream requests without stripping existing headers.

## Provider Credential Handling: Two Modes

The proxy supports distinct strategies for managing provider API keys, each with different security properties.

### BYOK Mode: Pass-Through Authentication

In **bring-your-own-key** mode, applications supply their own provider credentials via standard headers (`Authorization`, `x-api-key`, etc.). The proxy forwards these **unchanged**:

- **OpenAI**: `Authorization: Bearer sk-...` passes directly through
- **Anthropic**: `x-api-key: sk-ant-...` preserved intact
- **Vertex**: `Authorization: Bearer $(gcloud auth print-access-token)` forwarded as-is
- **Bedrock**: AWS signature headers passed without modification

The [`proxy/providers/adapter_contract_test.go`](https://github.com/JuliusBrussee/caveman/blob/main/proxy/providers/adapter_contract_test.go) (lines 152-185) enforces this contract across all providers, ensuring that any header present in the incoming request survives to the upstream call.

### Stored Key Mode: Secure Injection

When configured for **stored credentials**, the proxy retrieves encrypted provider keys from Caveman Cloud and injects them at request time. This mode:

- Eliminates provider keys from application code
- Enables centralized key rotation and revocation
- Maintains audit trails through the gateway

The injection occurs after gateway authentication but before upstream dispatch, using the same header-preserving logic as BYOK mode.

## Credential Redaction and Logging Security

Credentials that appear in request payloads undergo systematic redaction before any logging or observability processing. The [`shared/platform/redact/payload_test.go`](https://github.com/JuliusBrussee/caveman/blob/main/shared/platform/redact/payload_test.go) file (lines 749-751) validates this behavior, confirming that patterns matching API key formats are replaced with `[REDACTED]` tokens.

This applies to:
- JSON request/response bodies containing key fields
- URL query parameters with sensitive values
- Header values in debug traces

The redaction layer operates at the platform level, ensuring consistent protection across all proxy components.

## CLI Integration and Runtime Configuration

The [`packages/cli/src/index.ts`](https://github.com/JuliusBrussee/caveman/blob/main/packages/cli/src/index.ts) file orchestrates proxy startup and credential propagation:

```typescript
// CLI startup sequence (simplified from index.ts lines 95-100, 18043-18050)
async function startProxy(): Promise<void> {
  const gatewayUrl = process.env.CAVE_GATEWAY_URL ?? await getPersistedUrl();
  const apiKey = process.env.CAVE_API_KEY ?? await loadFromEnvFile();
  
  const proxy = spawn('caveman-proxy', [], {
    env: {
      ...process.env,
      CAVE_API_KEY: apiKey,
      CAVE_GATEWAY_URL: gatewayUrl,
    }
  });
  
  // Write run-state for other CLI commands
  await writeRunState({ gatewayUrl, pid: proxy.pid });
}

```

The run-state file maintains active session information, including which gateway secret is in use, enabling subsequent CLI operations to authenticate against the proxy without redundant environment configuration.

## Security Boundaries and Threat Model

The proxy architecture establishes clear trust boundaries:

| Layer | Responsibility | Credential Handling |
|-------|--------------|---------------------|
| **Application** | Business logic | Never sees `CAVE_API_KEY`; may hold provider keys in BYOK |
| **Proxy** | Authentication & routing | Injects gateway auth; forwards or injects provider auth |
| **Provider** | Model inference | Receives authenticated, authorized requests only |

This structure prevents:
- **Credential leakage**: Provider keys never logged or returned to callers
- **Gateway forgery**: `CAVE_API_KEY` required for all proxied traffic
- **Cross-tenant access**: Gateway keys scoped to specific Caveman workspaces

## Summary

- **`CAVE_API_KEY`** environment variable provides gateway authentication, injected as `x-cave-api-key` header by the proxy
- **Provider credentials** pass through unchanged in BYOK mode or get securely injected from encrypted storage
- **Redaction logic** in `shared/platform/redact` ensures credentials never appear in logs
- **CLI startup** at [`packages/cli/src/index.ts`](https://github.com/JuliusBrussee/caveman/blob/main/packages/cli/src/index.ts) propagates credentials to the proxy process via environment variables
- **Contract tests** in `proxy/providers/*/vertex_test.go`, [`bedrock_test.go`](https://github.com/JuliusBrussee/caveman/blob/main/bedrock_test.go), and [`adapter_contract_test.go`](https://github.com/JuliusBrussee/caveman/blob/main/adapter_contract_test.go) verify header preservation across all code paths

## Frequently Asked Questions

### Where do I set the CAVE_API_KEY for the proxy?

Set `CAVE_API_KEY` as an environment variable before running `caveman start`. The CLI automatically propagates this value to the proxy process. You can also define it in a `.env` file in your project root for local development.

### Does the proxy modify my OpenAI or Anthropic API keys?

No. In BYOK mode, all provider headers pass through unchanged. The proxy only adds the `x-cave-api-key` header for gateway authentication. Provider-specific credentials remain exactly as your application supplies them.

### How does Caveman prevent API keys from leaking in logs?

The `shared/platform/redact` package scans all request and response payloads for credential patterns before logging. Any detected keys are replaced with `[REDACTED]` tokens. This operates at the platform layer, protecting against accidental exposure in debug output or error traces.

### Can I use stored provider keys instead of BYOK?

Yes. When you configure provider keys through Caveman Cloud, the proxy retrieves and injects them automatically. Your application sends requests without provider credentials, and the proxy adds the appropriate authentication before forwarding to the upstream API.