OAuth 1.0a Signer

OAuth 1.0a Signer

The agentsec-signer crate is a standalone sidecar that signs requests with OAuth 1.0a (HMAC-SHA1, RFC 5849). Use it for APIs that require OAuth 1.0a authentication, like the Twitter/X API.

How It Works

TAP Proxy                  OAuth Signer               Twitter API
     |                               |                          |
     |  POST /                       |                          |
     |  X-OAuth-Credential: twitter  |                          |
     |  X-OAuth-Target: https://...  |                          |
     |  X-TAP-Method: POST      |                          |
     |  body: {"text":"Hello"}       |                          |
     | ------------------------------>|                          |
     |                               |  Signs with HMAC-SHA1   |
     |                               |  POST https://...        |
     |                               |  Authorization: OAuth .. |
     |                               | ------------------------>|
     |                               |                          |
     |                               |  Response               |
     |                <--------------|<-------------------------|
  1. Receives a request with X-OAuth-Credential (credential name) and X-OAuth-Target (real API URL)
  2. Loads the credential’s consumer key, consumer secret, access token, and access token secret from env vars
  3. Builds an OAuth 1.0a signature (nonce, timestamp, signature base string, HMAC-SHA1)
  4. Forwards the request to the real API with the signed Authorization header
  5. Returns the upstream response (auth headers stripped)

Setup

1. Configure TAP

Register the credential via the admin API or CLI. The credential uses the sidecar connector pointing at the signer.

Via admin API:

curl -X POST https://proxy.toolsec.org/admin/credentials \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "twitter",
    "description": "Twitter API v2",
    "connector": "sidecar",
    "api_base": "http://oauth-signer:8080"
  }'

Via CLI (self-hosted):

tap add \
  --db agentsec.db \
  --encryption-key $AGENTSEC_ENCRYPTION_KEY \
  --name twitter \
  --description "Twitter API v2" \
  --auth oauth1 \
  --api-base http://oauth-signer:8080

2. Set Environment Variables

Each credential requires four env vars following this pattern:

OAUTH_CRED_{NAME}_CONSUMER_KEY=your-consumer-key
OAUTH_CRED_{NAME}_CONSUMER_SECRET=your-consumer-secret
OAUTH_CRED_{NAME}_ACCESS_TOKEN=your-access-token
OAUTH_CRED_{NAME}_ACCESS_TOKEN_SECRET=your-access-token-secret

The signer auto-discovers credentials by scanning for OAUTH_CRED_*_CONSUMER_KEY env vars at startup.

Example for Twitter:

OAUTH_CRED_TWITTER_CONSUMER_KEY=xvz1evFS4wEEPTGEFPHBog
OAUTH_CRED_TWITTER_CONSUMER_SECRET=kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw
OAUTH_CRED_TWITTER_ACCESS_TOKEN=370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb
OAUTH_CRED_TWITTER_ACCESS_TOKEN_SECRET=LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE

3. Add to Docker Compose

services:
  oauth-signer:
    build:
      context: .
      dockerfile: Dockerfile.signer  # or use the same Dockerfile with different target
    ports:
      - "8080:8080"
    environment:
      - OAUTH_SIGNER_PORT=8080
      - OAUTH_CRED_TWITTER_CONSUMER_KEY
      - OAUTH_CRED_TWITTER_CONSUMER_SECRET
      - OAUTH_CRED_TWITTER_ACCESS_TOKEN
      - OAUTH_CRED_TWITTER_ACCESS_TOKEN_SECRET

4. Test

# Check signer health (lists discovered credentials)
curl http://localhost:8080/health
 
# Post a tweet through TAP
curl -X POST https://proxy.toolsec.org/forward \
  -H "X-TAP-Key: $MY_AGENT_KEY" \
  -H "X-TAP-Credential: twitter" \
  -H "X-TAP-Target: https://api.twitter.com/2/tweets" \
  -H "X-TAP-Method: POST" \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello from TAP!"}'

Signer API

EndpointMethodDescription
/ANYSign and forward request. Requires X-OAuth-Credential and X-OAuth-Target headers
/healthGETHealth check, returns list of loaded credentials

Port: Configurable via OAUTH_SIGNER_PORT (default 8080).

The X-TAP-Method header tells the signer which HTTP method to use for signing and forwarding (since the proxy always sends via POST).