> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agtos.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> Authentication, encryption, rate limiting, and data privacy in agtOS

agtOS is designed for self-hosted deployment where you control your own data. This page consolidates all security features and configuration.

## API Authentication

REST API authentication is **opt-in**. When the `AGTOS_API_KEY` environment variable is set, all `/api/*` endpoints require a Bearer token.

```bash theme={null}
# Enable authentication
AGTOS_API_KEY=your-secret-key-here
```

```bash theme={null}
# Authenticated request
curl -H "Authorization: Bearer your-secret-key-here" \
  http://localhost:4102/api/health
```

**Exempt paths** (never require auth):

* `/health` and sub-paths — for monitoring and health checks
* `/metrics` — for Prometheus scraping
* `/api/credentials/validate` — read-only key validation
* `/api/setup-token` — localhost-only, onboarding token retrieval

The API key is compared using SHA-256 hashing with `crypto.timingSafeEqual` to prevent timing attacks.

<Warning>
  In production, always set `AGTOS_API_KEY`. Without it, all API endpoints are unauthenticated — anyone on the network can access them.
</Warning>

## Rate Limiting

All API endpoints are rate-limited using a token bucket algorithm per client IP:

| Scope                    | Default     | Config Variable   |
| ------------------------ | ----------- | ----------------- |
| General API (`/api/*`)   | 100 req/min | `API_RATE_LIMIT`  |
| Chat, Tasks, Credentials | 20 req/min  | `CHAT_RATE_LIMIT` |

Rate limit headers are included on every response (`X-RateLimit-Remaining`). Exceeded requests receive `429 Too Many Requests`.

## Credential Encryption

API keys for cloud providers (Claude, OpenAI, OpenRouter) are encrypted at rest in `~/.agtos/credentials.json` using **AES-256-GCM**:

* **Algorithm**: AES-256-GCM (authenticated encryption with AAD binding per provider)
* **Key derivation**: scrypt (N=16384, r=8, p=1) — auto-migrates legacy PBKDF2 files
* **Salt**: 32 bytes, persisted at `~/.agtos/.salt` (auto-generated on first use)
* **Machine secret**: 32 bytes, persisted at `~/.agtos/.secret` (auto-generated on first use)
* **IV**: Random 12 bytes per encryption (per NIST SP 800-38D)
* **File permissions**: 0o600 (owner read/write only)

```bash theme={null}
# For Docker/CI — set these env vars so credentials persist across restarts
AGTOS_CREDENTIAL_SECRET=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
AGTOS_CREDENTIAL_SALT=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
```

<Note>
  On desktop/local installs, the machine secret and salt are auto-generated and persisted to `~/.agtos/`. No manual configuration is needed. For Docker deployments, set `AGTOS_CREDENTIAL_SECRET` and `AGTOS_CREDENTIAL_SALT` as environment variables.
</Note>

## Device Authentication

Hardware devices (ESP32, browsers) authenticate using per-device shared secrets. The secret is hashed with SHA-256 before storage — the plaintext is never persisted.

Devices progress through a trust lifecycle:

| Trust Level | Value | Meaning                         |
| ----------- | ----- | ------------------------------- |
| Anonymous   | 0     | No authentication               |
| Basic       | 1     | API key authenticated           |
| Verified    | 2     | Device-specific secret provided |
| Trusted     | 3     | Verified + established history  |

## Input Validation

All POST endpoints validate input with [Zod](https://zod.dev) schemas:

* **Text limits**: Chat messages max 10,000 characters, memory questions max 2,000 characters
* **Body size**: Request bodies capped at 1 MB
* **ID format**: Path parameter IDs must match `^[a-zA-Z0-9\-_]+$` (1-128 characters)
* **Type safety**: All fields are type-checked with constraints (min/max, enums, patterns)

Invalid input returns `400 Bad Request` with field-level error details.

## Network Security

### CORS

Cross-Origin Resource Sharing is configured via `CORS_ORIGIN`:

```bash theme={null}
# Default: localhost only
CORS_ORIGIN=http://localhost:5173

# Allow all origins (not recommended for production)
CORS_ORIGIN=*

# Multiple origins
CORS_ORIGIN=https://app.example.com,https://admin.example.com
```

Tauri desktop app origins (`tauri://localhost`, `https://tauri.localhost`) are always included automatically.

### Credential Storage Endpoint

`POST /api/credentials` is **localhost-only** and requires authentication (API key or setup token) — requests from non-loopback addresses receive `403 Forbidden`. This ensures API keys can only be stored from the same machine during onboarding.

### mDNS

mDNS device discovery is **opt-in** (`AGTOS_MDNS_ENABLED=false` by default). When enabled, agtOS broadcasts its presence on the local network for zero-config ESP32 discovery. Disable in untrusted network environments.

## Data Privacy

* **BYOK (Bring Your Own Key)** — agtOS never stores or transmits your API keys to any third party. Keys are encrypted locally and used only for direct API calls to the providers you configure.
* **Local-first** — all processing (voice, memory, scheduling) runs on your machine. Cloud providers receive only the messages you send to them.
* **Memory controls** — configurable retention period (default 30 days), per-user privacy settings, and explicit delete APIs.
* **No telemetry** — agtOS does not collect usage data, analytics, or crash reports.

## Production Checklist

<Steps>
  <Step title="Set AGTOS_API_KEY">
    Protect all API endpoints with Bearer token authentication.
  </Step>

  <Step title="Set credential encryption secrets">
    For Docker/CI, set `AGTOS_CREDENTIAL_SECRET` and `AGTOS_CREDENTIAL_SALT` env vars for persistent encrypted credential storage across container restarts. Desktop installs auto-generate these at `~/.agtos/.secret` and `~/.agtos/.salt`.
  </Step>

  <Step title="Configure CORS">
    Restrict `CORS_ORIGIN` to your specific frontend domains.
  </Step>

  <Step title="Set NODE_ENV=production">
    Enables structured JSON logging and enforces credential salt requirements.
  </Step>

  <Step title="Review rate limits">
    Adjust `API_RATE_LIMIT` and `CHAT_RATE_LIMIT` based on expected traffic.
  </Step>

  <Step title="Disable mDNS">
    Keep `AGTOS_MDNS_ENABLED=false` unless you need ESP32 zero-config discovery.
  </Step>
</Steps>
