Claude
Skills
Sign in
Back

cc-gateway-ai-proxy

Included with Lifetime
$97 forever

Deploy and configure CC Gateway, a reverse proxy that normalizes Claude Code device fingerprints and telemetry for privacy-preserving API proxying

Backend & APIs

What this skill does


# CC Gateway — AI API Identity Gateway

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

CC Gateway is a TypeScript reverse proxy that sits between Claude Code clients and the Anthropic API. It normalizes 40+ device fingerprint dimensions (device ID, email, environment, RAM, headers, and system prompt content) to a single canonical identity, manages OAuth token refresh centrally, and prevents telemetry leakage from multi-machine setups.

## Architecture Overview

```
Client (Claude Code + env vars + Clash)
  └─► CC Gateway (rewrite + auth inject + SSE passthrough)
        └─► api.anthropic.com (single canonical identity)
              
Gateway also contacts:
  platform.claude.com (OAuth token refresh only)
```

**Three-layer defense:**
| Layer | Mechanism |
|-------|-----------|
| Env vars | Route CC traffic to gateway, disable side channels |
| Clash rules | Block any direct Anthropic connections at network level |
| Gateway | Rewrite all 40+ fingerprint dimensions in-flight |

## Installation

### Prerequisites
- Node.js 18+ or Docker
- A machine that has previously logged into Claude Code (for OAuth token extraction)

### Clone and Install

```bash
git clone https://github.com/motiful/cc-gateway.git
cd cc-gateway
npm install
```

### Generate Identity and Tokens

```bash
# Create a stable canonical identity (device_id, email, env profile)
npm run generate-identity

# Create a bearer token for a specific client machine
npm run generate-token my-laptop
npm run generate-token work-desktop
```

### Extract OAuth Token (from a logged-in machine)

```bash
# macOS — copies refresh_token from Keychain
bash scripts/extract-token.sh
```

### Configure

```bash
cp config.example.yaml config.yaml
```

Edit `config.yaml`:

```yaml
# config.yaml
identity:
  device_id: "GENERATED_DEVICE_ID"          # from generate-identity
  email: "[email protected]"
  platform: "darwin"
  arch: "arm64"
  node_version: "20.11.0"
  shell: "/bin/zsh"
  home: "/Users/canonical"
  working_directory: "/Users/canonical/projects"
  memory_gb: 16                              # canonical RAM value

oauth:
  refresh_token: "EXTRACTED_REFRESH_TOKEN"  # from extract-token.sh

clients:
  - name: my-laptop
    token: "GENERATED_CLIENT_TOKEN"
  - name: work-desktop
    token: "ANOTHER_CLIENT_TOKEN"

server:
  port: 8443
  tls: false                                 # true for production with certs
```

## Starting the Gateway

```bash
# Development (no TLS, hot reload)
npm run dev

# Production build
npm run build && npm start

# Docker Compose (recommended for production)
docker-compose up -d
```

### Docker Compose Example

```yaml
# docker-compose.yml
version: "3.8"
services:
  cc-gateway:
    build: .
    ports:
      - "8443:8443"
    volumes:
      - ./config.yaml:/app/config.yaml:ro
    restart: unless-stopped
    environment:
      - NODE_ENV=production
```

## Verification

```bash
# Health check
curl http://localhost:8443/_health

# Show before/after rewrite diff (requires client token)
curl -H "Authorization: Bearer YOUR_CLIENT_TOKEN" \
     http://localhost:8443/_verify
```

## Client Machine Setup

On each machine running Claude Code, set these environment variables:

```bash
# ~/.bashrc or ~/.zshrc

# Route all Claude Code API traffic through the gateway
export ANTHROPIC_BASE_URL="https://gateway.your-domain.com:8443"

# Disable side-channel telemetry (Datadog, GrowthBook, version checks)
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1

# Skip browser OAuth — gateway handles authentication
export CLAUDE_CODE_OAUTH_TOKEN="gateway-managed"

# Authenticate to the gateway with the per-machine token
export ANTHROPIC_CUSTOM_HEADERS="Proxy-Authorization: Bearer YOUR_CLIENT_TOKEN"
```

Or use the interactive setup script:

```bash
bash scripts/client-setup.sh
```

Then just run `claude` — no login prompt required.

## Clash Rules (Network-Level Blocking)

Add to your Clash configuration to block any direct Anthropic connections:

```yaml
# clash-rules.yaml excerpt
rules:
  - DOMAIN,gateway.your-domain.com,DIRECT      # Allow your gateway
  - DOMAIN-SUFFIX,anthropic.com,REJECT          # Block direct API calls
  - DOMAIN-SUFFIX,claude.com,REJECT             # Block direct OAuth
  - DOMAIN-SUFFIX,claude.ai,REJECT              # Block Claude web
  - DOMAIN-SUFFIX,datadoghq.com,REJECT          # Block Datadog telemetry
  - DOMAIN-SUFFIX,statsig.com,REJECT            # Block feature flags
```

See `clash-rules.yaml` in the repo for the full template.

## What Gets Rewritten

| Layer | Field | Transformation |
|-------|-------|----------------|
| Identity | `device_id` | → canonical ID from config |
| Identity | `email` | → canonical email |
| Environment | `env` object (40+ fields) | → entire object replaced |
| Process | `constrainedMemory` (physical RAM) | → canonical value |
| Process | `rss`, `heapTotal`, `heapUsed` | → randomized in realistic range |
| Headers | `User-Agent` | → canonical CC version string |
| Headers | `Authorization` | → real OAuth token (injected) |
| Headers | `x-anthropic-billing-header` | → canonical fingerprint |
| Prompt text | `Platform`, `Shell`, `OS Version` | → canonical values |
| Prompt text | `/Users/xxx/`, `/home/xxx/` | → canonical home prefix |
| Leak fields | `baseUrl` | → stripped |
| Leak fields | `gateway` provider field | → stripped |

## TypeScript Usage Examples

### Custom Rewriter Extension

```typescript
// src/rewriters/custom-field-rewriter.ts
import { RequestRewriter } from '../types';

export const customFieldRewriter: RequestRewriter = {
  name: 'custom-field-rewriter',
  
  rewriteBody(body: Record<string, unknown>, config: CanonicalConfig): Record<string, unknown> {
    // Strip any custom analytics fields your org adds
    const { __analytics, __session_debug, ...cleaned } = body as any;
    
    // Normalize any additional identity fields
    if (cleaned.metadata?.user_id) {
      cleaned.metadata.user_id = config.identity.device_id;
    }
    
    return cleaned;
  },
  
  rewriteHeaders(headers: Record<string, string>, config: CanonicalConfig): Record<string, string> {
    return {
      ...headers,
      'x-custom-client': 'canonical',
    };
  }
};
```

### Programmatic Gateway Start

```typescript
// scripts/start-with-monitoring.ts
import { createGateway } from '../src/gateway';
import { loadConfig } from '../src/config';

async function main() {
  const config = await loadConfig('./config.yaml');
  
  const gateway = await createGateway(config);
  
  gateway.on('request', ({ clientId, path }) => {
    console.log(`[${new Date().toISOString()}] ${clientId} → ${path}`);
  });
  
  gateway.on('rewrite', ({ field, before, after }) => {
    console.log(`Rewrote ${field}: ${before} → ${after}`);
  });
  
  gateway.on('tokenRefresh', ({ expiresAt }) => {
    console.log(`OAuth token refreshed, expires: ${expiresAt}`);
  });
  
  await gateway.listen(config.server.port);
  console.log(`Gateway running on port ${config.server.port}`);
}

main().catch(console.error);
```

### Token Generation (Programmatic)

```typescript
// scripts/provision-client.ts
import { generateClientToken, addClientToConfig } from '../src/auth';

async function provisionNewMachine(machineName: string) {
  const token = await generateClientToken(machineName);
  
  await addClientToConfig('./config.yaml', {
    name: machineName,
    token,
    created_at: new Date().toISOString(),
  });
  
  console.log(`Client token for ${machineName}:`);
  console.log(token);
  console.log('\nAdd to client machine:');
  console.log(`export ANTHROPIC_CUSTOM_HEADERS="Proxy-Authorization: Bearer ${token}"`);
}

provisionNewMachine(process.argv[2] ?? 'new-machine');
```

## Key npm Scripts

| Command | Purpose |
|---------|---------|
| `npm run dev` | Start with hot reload (development) |
| `npm run build` | Compile TypeScript to `dist/` |
| `npm start` | Run compiled production build |
| `npm test` | Run rewriter test suite (13 tests) |
| `npm run gen

Related in Backend & APIs