> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sec0.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Network Gateway

> Enforce auth, quotas, entitlements, and custody at network boundaries.

`sec0-sdk/gateway` centralizes authentication, authorization, entitlements, quotas, vendor token brokering, idempotency/dedupe, and audit at **network boundaries**. Use it when tool execution crosses process or network boundaries so custody and policy enforcement continue across hops.

## When to Use the Gateway

* Your agents call tool servers over HTTP/HTTPS
* You need centralized OIDC auth at the network edge
* You want per-tenant/per-user rate limits and daily quotas
* You need vendor API key injection without exposing keys to agents
* You want idempotency/dedupe for side-effecting tool calls
* You need egress and filesystem allowlists at the boundary

## Starting the Gateway

```typescript theme={null}
import { startGatewayServer, InMemoryAdapter } from "sec0-sdk/gateway";
import { Sec0Appender } from "sec0-sdk/audit";
import { LocalDevSigner } from "sec0-sdk/signer";

const signer = LocalDevSigner.fromKeyRef("file://./.sec0/keys/ed25519.key");
const appender = new Sec0Appender({ config: { dir: ".sec0" }, signer });

startGatewayServer({
  port: 8088,
  tenant: "my-app",

  // Map server names to upstream base URLs
  targets: {
    "vision-mcp": "https://vision.example.com",
    "database-mcp": "https://db.example.com",
    "stripe-mcp": "https://stripe-adapter.example.com",
  },

  // Required: audit sink
  audit: {
    append: (env) => appender.append(env),
    gatewayName: "sec0.gateway",
    gatewayVersion: "1.0.0",
  },

  // Required: quota adapter
  quotas: { adapter: new InMemoryAdapter() },

  // Start in observe mode, then switch to enforce
  enforcement: { mode: "observe" },
});
```

## Gateway Endpoints

| Endpoint                           | Description                         |
| ---------------------------------- | ----------------------------------- |
| `POST /mcp/:server/:toolAtVersion` | Invoke a tool on an upstream server |
| `POST /a2a/invoke`                 | Agent-to-agent convenience envelope |

### Required Headers

| Header              | Purpose                                                              |
| ------------------- | -------------------------------------------------------------------- |
| `x-idempotency-key` | Required when dedupe or side-effect idempotency policies are enabled |
| `x-node-id`         | Agent state: node identifier                                         |
| `x-agent-ref`       | Agent state: run reference                                           |
| `x-agent-state`     | Agent state: full encoded payload                                    |

## Authentication

### OIDC JWT Validation

```typescript theme={null}
startGatewayServer({
  // ...
  authn: {
    allowUnauthenticated: false,
    oidc: {
      issuer: "https://auth.example.com",
      audience: "sec0.gateway",
      jwks_uri: "https://auth.example.com/.well-known/jwks.json",
      tenantClaim: "org",
      userClaim: "email",
      rolesClaim: "roles",
      subjectClaim: "sub",
      clientIdClaim: "azp",
    },
  },
});
```

For machine-to-machine agents, use OIDC client-credentials tokens (the gateway
can authorize these via `agents` entitlements using the token `azp/client_id` claim).

## Entitlements

Control which tenants, users, roles, and service agents can access which tools:

```typescript theme={null}
startGatewayServer({
  // ...
  entitlements: {
    default_plan: "free",
    plans: {
      free: { calls_per_day: 1000 },
      pro: { calls_per_day: 100000 },
    },
    tenants: {
      "acme-corp": {
        plan: "pro",
        allowlist: [],
        denylist: ["mcp://payments/refund@2.0"],
        per_tool: {
          "mcp://fetch/fetch.get@1.0": { rate_per_sec: 10, calls_per_day: 50000 },
        },
        users: {
          "admin@acme.com": { allowlist: ["*"] },
          "readonly@acme.com": { allowlist: ["mcp://fetch/*@1.*"] },
        },
        user_ids: {
          "auth0|usr_123": { allowlist: ["mcp://ehr/patient.read@r4"] },
        },
        roles: {
          "security-analyst": { allowlist: ["mcp://posture/*@1.*"] },
          "contractor": { denylist: ["mcp://payments/*@2.*"] },
        },
        agents: {
          "sec0-orchestrator-prod": { allowlist: ["mcp://payments/charge@2.*"] },
        },
        agent_nodes: {
          "workflow-planner": { allowlist: ["mcp://planner/*@1.*"] },
        },
      },
    },
  },
});
```

## Quotas

Rate limiting and daily limits via pluggable adapters:

```typescript theme={null}
import { InMemoryAdapter } from "sec0-sdk/gateway";

startGatewayServer({
  // ...
  quotas: {
    adapter: new InMemoryAdapter(),
    // Or use a Redis adapter for production:
    // adapter: new RedisAdapter({ url: process.env.REDIS_URL }),
  },
});
```

### QuotaAdapter Interface

```typescript theme={null}
interface QuotaAdapter {
  incrDaily(tenant: string, tool: string, limit: number, now?: Date):
    Promise<{ count: number; resetAt: Date }>;
  takeToken(tenant: string, tool: string, ratePerSec: number, burst?: number, now?: Date):
    Promise<{ tokens: number; resetAt: Date }>;
}
```

## Vendor Token Brokering

Inject upstream API keys without exposing them to agents:

```typescript theme={null}
startGatewayServer({
  // ...
  brokers: {
    "stripe-mcp": {
      type: "vendor_key_pool",
      key_refs: [
        "file:///etc/sec0/stripe-key-1.txt",
        "file:///etc/sec0/stripe-key-2.txt",
      ],
      inject: {
        header: "Authorization",
        format: "bearer",
      },
    },
  },
});
```

### Broker Types

| Type              | Description                                |
| ----------------- | ------------------------------------------ |
| `vendor_key_pool` | Round-robin from a pool of API keys        |
| `oidc_on_behalf`  | Exchange tokens via OIDC on-behalf-of flow |
| `static`          | Inject a single static key                 |

## Boundary Guardrails

Restrict what upstream servers can access:

```typescript theme={null}
startGatewayServer({
  // ...
  security: {
    egress_allowlist: ["*.example.com", "api.stripe.com"],
    fs_allowlist: ["/tmp/sec0-*"],
    limits: {
      max_payload_kb: 1024,
      max_duration_ms: 30000,
    },
    side_effects: {
      require_idempotency_key: true,
      approve_high_risk: true,
    },
    allow_versions: {
      "vision-mcp": ["1.0.0", "1.1.0"],
      "database-mcp": ["2.*"],
    },
  },
});
```

## Idempotency & Dedupe

Prevent duplicate side-effect calls:

```typescript theme={null}
startGatewayServer({
  // ...
  dedupe: {
    enabled: true,
    duplicatePolicy: "replay",  // "replay" | "reject"
    ttlSec: 3600,               // Cache window
    namespace: "sec0-gw",       // Key prefix
    redisUrl: process.env.REDIS_URL,  // Optional Redis backend
  },
});
```

## AP2 Mandate Enforcement

Verify multi-hop intent and cart mandates:

```typescript theme={null}
startGatewayServer({
  // ...
  ap2: {
    enabled: true,
    requireForSideEffects: true,
    headers: {
      intent: "x-ap2-intent-mandate",
      cart: "x-ap2-cart-mandate",
      bundle: "x-ap2-bundle",
    },
    trust: {
      didMethods: ["did:web"],
      issuersAllowlist: ["did:web:example.com"],
      clockSkewSec: 60,
    },
    mode: "full",  // "" | "observe" | "partial" | "full"
  },
});
```

## Agent State Analytics

Opt-in to derived telemetry written into agent state:

```typescript theme={null}
startGatewayServer({
  // ...
  agentState: {
    enableGatewayAnalytics: true,
    includeAp2: true,
    includeRisk: true,
  },
});
```

## Remote Runtime Decisioning

Use the gateway's runtime adapter when final allow or deny decisions should be delegated to a remote service:

```typescript theme={null}
startGatewayServer({
  // ...
  runtime: {
    enforcement: {
      mode: "remote",
      protocolVersion: "2026-02-01",
      failureMode: "local",
      remote: {
        endpoint: process.env.SEC0_RUNTIME_URL!,
        apiKey: process.env.SEC0_RUNTIME_API_KEY,
        timeoutMs: 3000,
      },
    },
  },
});
```

## Using the Pipeline Directly

If you already have an HTTP server, use the lower-level pipeline:

```typescript theme={null}
import { gatewayPipeline } from "sec0-sdk/gateway";

// In your route handler:
await gatewayPipeline(config, serverName, toolAtVersion, ctx, span, next);
```

## Policy-Driven Configuration

Map a Sec0 policy YAML into gateway config:

```typescript theme={null}
startGatewayServer({
  port: 8088,
  tenant: "my-app",
  targets: { /* ... */ },
  policyYaml: fs.readFileSync("./policy.yaml", "utf8"),
  // ... audit and quotas still required
});
```

For the full gateway configuration reference, see [Gateway Config Reference](/docs/reference/gateway-config).
