Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Authentication & Authorization

Townhall supports multiple authentication modes and fine-grained authorization scopes for secure remote access.

Authentication Modes

None (Default)

No authentication required. Only safe on loopback (127.0.0.1).

[townhall.auth]
mode = "none"  # Default

⚠️ Security: Townhall will refuse to start if binding to non-loopback addresses with mode = "none".

API Key

Secure token-based authentication using Argon2id password hashing.

[townhall.auth]
mode = "api_key"
api_key_hash = "$argon2id$v=19$m=19456,t=2,p=1$..."
api_key_scopes = ["town.read", "town.write"]  # Optional: restrict scopes

Generating an API Key

# Generate a new API key (outputs raw key and hash)
tt generate-api-key

# Output:
# API Key: abc123def456...
# Hash: $argon2id$v=19$m=19456,t=2,p=1$...
#
# Add to tinytown.toml:
# [townhall.auth]
# mode = "api_key"
# api_key_hash = "$argon2id$v=19$..."

Important: Store the raw API key securely. Only the hash is stored in config.

Using API Keys

Pass the key via Authorization header or X-API-Key:

# Bearer token (recommended)
curl -H "Authorization: Bearer <your-api-key>" \
  http://localhost:8787/v1/status

# X-API-Key header
curl -H "X-API-Key: <your-api-key>" \
  http://localhost:8787/v1/status

OIDC (Coming Soon)

OpenID Connect authentication for enterprise deployments.

[townhall.auth]
mode = "oidc"
issuer = "https://issuer.example.com"
audience = "tinytown-api"
jwks_url = "https://issuer.example.com/.well-known/jwks.json"
required_scopes = ["tinytown:access"]
clock_skew_seconds = 60

Authorization Scopes

All endpoints require specific scopes for access:

ScopeDescriptionEndpoints
town.readRead status and agent infoGET /v1/*, inbox
town.writeAssign tasks, send messagesPOST /v1/tasks/*, messages, backlog
agent.manageSpawn/kill/restart agentsPOST /v1/agents, recovery
adminFull access (grants all scopes)All endpoints

Configuring Scopes

For API key auth, configure allowed scopes:

[townhall.auth]
mode = "api_key"
api_key_hash = "..."
api_key_scopes = ["town.read", "town.write"]  # Read/write but no agent management

Empty api_key_scopes grants admin access (all scopes).

Audit Logging

All mutating operations (POST, PUT, DELETE, PATCH) are logged:

INFO audit: operation completed request_id="abc123" principal="api_key" method="POST" path="/v1/agents" result="success"
WARN audit: operation denied request_id="def456" principal="api_key" method="POST" path="/v1/recover" result="denied"

Audit events include:

  • Request ID - Unique identifier for correlation
  • Principal ID - Who made the request
  • Scopes - What permissions they had
  • Method/Path - What they tried to do
  • Result - success, denied, or error

Security Notes

  • Authorization headers are never logged
  • API keys are stored as Argon2id hashes, never plaintext
  • Auth errors use constant-time responses to prevent timing attacks

TLS Configuration

For production deployments, enable TLS:

[townhall.tls]
enabled = true
cert_path = "/path/to/server.crt"
key_path = "/path/to/server.key"

Mutual TLS (mTLS)

For service-to-service authentication:

[townhall.mtls]
enabled = true
required = true  # Reject clients without valid certs
ca_path = "/path/to/ca.crt"

Security Best Practices

  1. Local development: Use mode = "none" with bind = "127.0.0.1"
  2. Team access: Use mode = "api_key" with TLS
  3. Production: Use mode = "oidc" with TLS and mTLS
  4. Always scope API keys to minimum required permissions
  5. Rotate API keys regularly