@openape/proxy
v0.4.3
Published
OpenApe agent HTTP gateway — forward proxy with grant-based access control
Downloads
1,915
Readme
@openape/proxy
HTTP forward proxy for AI agent traffic control. Sits between an agent and the internet, enforcing grant-based access rules before forwarding requests.
┌─────────┐ HTTP (plain) ┌─────────────┐ HTTPS ┌──────────┐
│ Agent │ ──────────────► │ OpenApe │ ────────► │ Upstream │
│ │ ◄────────────── │ Proxy │ ◄──────── │ Server │
└─────────┘ └──────┬──────┘ └──────────┘
│
grant request
│
┌──────▼──────┐
│ IdP │
│ (Grants) │
└─────────────┘The proxy operates at the application level (not CONNECT tunnel) — it sees the full request (domain, method, path, headers, body) and can match against fine-grained rules.
Installation
npm install @openape/proxyUsage
openape-proxy --config config.toml
openape-proxy --config config.toml --dry-run # Log only, no blockingConfiguration
Configuration uses TOML format:
[proxy]
listen = "127.0.0.1:9090"
idp_url = "https://id.example.com"
agent_email = "[email protected]"
default_action = "block"
# Always allow (no grant needed)
[[allow]]
domain = "*.internal.example.com"
methods = ["GET"]
note = "Internal read-only access"
# Always deny (regardless of grants)
[[deny]]
domain = "169.254.169.254"
note = "Cloud metadata endpoint"
# Require a grant
[[grant_required]]
domain = "api.github.com"
path = "/repos/*/issues"
methods = ["POST"]
grant_type = "once"
permissions = ["write:issues"]
duration = 3600Proxy Options
| Option | Type | Description |
|--------|------|-------------|
| listen | string | Bind address and port |
| idp_url | string | IdP URL for grant requests |
| agent_email | string | Agent identity |
| default_action | string | Action when no rule matches (see below) |
Audit data is not written to disk locally. The proxy emits an operator-readable summary line to stderr for each decision; the trustworthy, tamper-resistant audit is recorded server-side by the IdP every time it processes a grant request. Anything stored on the agent's host is also writable by the agent, so it can't be relied on as evidence.
Rule Options
| Option | Type | Description |
|--------|------|-------------|
| domain | string | Domain pattern (supports * wildcards) |
| methods | string[] | HTTP methods (optional — all if omitted) |
| path | string | Path glob pattern (optional) |
| note | string | Human-readable note |
Grant rules additionally support:
| Option | Type | Description |
|--------|------|-------------|
| grant_type | string | 'once', 'timed', or 'always' |
| permissions | string[] | Required permissions |
| duration | number | Grant validity in seconds (for timed) |
Rule Hierarchy
Rules are evaluated in this order — first match wins:
deny— Always blocked, no exceptionsallow— Always permitted, no grant neededgrant_required— Permitted only with a valid grantdefault_action— Applied when no rule matches
Default Actions
| Action | Behavior |
|--------|----------|
| block | Reject the request immediately |
| request | Request a grant from the IdP and wait for approval (blocking) |
| request-async | Request a grant and return a pending response to the agent |
Agent Authentication
The agent authenticates to the proxy via the Proxy-Authorization header using a JWT from the existing Ed25519 challenge-response flow:
Proxy-Authorization: Bearer <JWT>Agent Integration
Configure your agent to use the proxy via environment variables:
export HTTP_PROXY=http://127.0.0.1:9090
export HTTPS_PROXY=http://127.0.0.1:9090The agent sends plain HTTP to the proxy on localhost. The proxy terminates the connection and forwards the request as HTTPS to the upstream server.
Audit Log
All requests are logged in JSONL format:
{
"ts": "2025-01-15T10:30:00.000Z",
"agent": "[email protected]",
"action": "grant_approved",
"domain": "api.github.com",
"method": "POST",
"path": "/repos/owner/repo/issues",
"grant_id": "550e8400-e29b-41d4-a716-446655440000",
"rule": "grant_required",
"waited_ms": 1250
}Possible action values: allow, deny, grant_approved, grant_denied, grant_timeout, error.
