How It Works

How It Works

Architecture

TAP is a Rust workspace with 5 crates:

CratePurpose
agentsec-coreShared types, SQLite ConfigStore with RBAC, AES-256-GCM credential encryption, ApprovalChannel trait
agentsec-proxyHTTP proxy service (axum) — the main runtime, including the admin API
agentsec-botTelegram approval bot, implements ApprovalChannel
agentsec-cliCLI tool: init, add, status, logs, test, agent, role, migrate
agentsec-signerOAuth 1.0a signing sidecar for Twitter/X

All configuration is stored in SQLite. There is no YAML config file. The ConfigStore manages teams, admins, credentials, agents, roles, policies, and cross-team agent links — all with team-scoped isolation.

Request Modes

TAP supports two ways for agents to reference credentials:

The agent sends a credential name via the X-TAP-Credential header. The proxy handles routing, auth header injection, and sidecar communication automatically.

POST /forward
X-TAP-Key: <agent-api-key>
X-TAP-Credential: slack
X-TAP-Target: https://slack.com/api/conversations.list
X-TAP-Method: GET

The agent never knows whether the credential is a simple API key or requires OAuth — the proxy abstracts that away.

Legacy Placeholder Mode

The agent uses <CREDENTIAL:name> placeholders in headers (and optionally in the request body). The proxy validates placeholder positions, requests approval, then substitutes real values before forwarding.

POST /forward
X-TAP-Key: <agent-api-key>
X-TAP-Target: https://api.openai.com/v1/chat/completions
Authorization: Bearer <CREDENTIAL:openai-key>
Content-Type: application/json

{"model": "gpt-4", "messages": [...]}

Security note: Placeholders are only allowed in authentication-related positions (Authorization header, X-Api-Key header, and opt-in body fields like token, api_key, access_token). Placeholders in non-auth positions (e.g., a tweet body or email subject) are rejected to prevent credential exfiltration through target APIs.

Connector Types

Each credential has a connector type that determines how the proxy routes requests:

Direct (Default)

For API keys and bearer tokens. The proxy injects the credential value into the Authorization header and forwards directly to the target URL. The auth header format defaults to Bearer {value} but is configurable per credential via the admin API (e.g., token={value} for custom formats).

Sidecar

For OAuth, custom protocols, or APIs that need request transformation. The proxy routes through an intermediary service at api_base (e.g., http://oauth-signer:8080 for OAuth 1.0a).

When relative_target: true, the agent sends a path (e.g., /sendMessage) instead of a full URL, and the proxy prepends api_base.

Request Flow

Agent request


Authentication (X-TAP-Key → HMAC-SHA256 hash lookup in SQLite)


Resolve target team (X-TAP-Team header, or default to agent's home team)


Parse credential reference (unified header or placeholders)


Whitelist check (is this credential allowed for this agent in this team?)


Rate limit check (per-agent request count against hourly limit)


Policy evaluation (auto-approve URL? auto-approve method? require approval?)

  ├─ Auto-approved → skip to Forward


Human approval (Telegram or passkey — see Policies & Approval)


Credential injection / placeholder substitution


Forward to target API (direct or via sidecar)


Response sanitization (scrub credential values from response body)


Audit log (JSON line with request ID, agent, team, credential name, status, latency)


Return response to agent

Multi-Tenant Architecture

All resources are scoped to teams:

  • Teams are the top-level isolation boundary. Each team has its own credentials, agents, roles, and policies.
  • Admins are humans who manage a team via the admin API. They authenticate with email + password and receive session tokens.
  • Agents are AI systems that authenticate with API keys and use credentials via the proxy.
  • Roles group credentials together. An agent’s effective permissions are the union of its direct credential assignments and its roles’ credentials.
  • Policies are per-credential rules that control auto-approve and require-approval behavior.

Team data is fully isolated — an admin in Team A cannot see or modify Team B’s credentials, agents, or policies.

Admin Authentication Flow

On managed hosting, use the admin dashboard at auth.toolsec.org for a visual interface. The admin API is also available for automation:

  1. SignupPOST /signup creates a team and admin account, sends a verification email
  2. Verify emailPOST /verify-email with the 6-digit code
  3. LoginPOST /login returns a 24-hour session token
  4. Admin API — all /admin/* endpoints require Authorization: Bearer <session_token>

Multi-Account (Cross-Team Access)

A single agent can access credentials across multiple teams. For example, a developer’s personal agent can use both personal API keys and company-managed credentials.

This works through the agent_team_links table. A company admin links an external agent into their team (optionally scoped to a specific role). The agent then uses the X-TAP-Team header to specify which team’s credentials to use.

See Multi-Account for details and examples.

Response Sanitization

Before returning API responses to the agent, the proxy scans for credential leakage:

  1. Exact match — scans for the literal credential value
  2. Base64 variant — scans for the base64-encoded credential
  3. URL-encoded variant — scans for the percent-encoded credential

Any matches are replaced with [REDACTED:credential-name]. Responses larger than 10 MB are passed through without scanning.

Trust Model

  • Agents are untrusted — they authenticate with API keys but cannot access credential values, cannot bypass policy, and see sanitized responses
  • The proxy is trusted — it holds encryption keys and decrypted credential values in memory during request processing
  • The approval channel is semi-trusted — approvers see request details but not credential values (approval messages are scrubbed)
  • Admins are trusted — they can create/delete credentials and agents, set policies, and link agents across teams. Credential values are write-only (never returned by the API)