How It Works
Architecture
TAP is a Rust workspace with 5 crates:
| Crate | Purpose |
|---|---|
agentsec-core | Shared types, SQLite ConfigStore with RBAC, AES-256-GCM credential encryption, ApprovalChannel trait |
agentsec-proxy | HTTP proxy service (axum) — the main runtime, including the admin API |
agentsec-bot | Telegram approval bot, implements ApprovalChannel |
agentsec-cli | CLI tool: init, add, status, logs, test, agent, role, migrate |
agentsec-signer | OAuth 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:
Unified Interface (Recommended)
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: GETThe 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 agentMulti-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:
- Signup —
POST /signupcreates a team and admin account, sends a verification email - Verify email —
POST /verify-emailwith the 6-digit code - Login —
POST /loginreturns a 24-hour session token - Admin API — all
/admin/*endpoints requireAuthorization: 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:
- Exact match — scans for the literal credential value
- Base64 variant — scans for the base64-encoded credential
- 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)