Repository navigation
Privacy and security
toard handles user accounts, ingest credentials, and usage data. Prompt and response text is a separate, optional capability. Read the collection boundary before enabling it.
By default, the shim reads usage metadata from local session files and sends normalized events to /api/v1/events. It does not send prompt or response text.
Typical metadata includes the provider and model, input/output/cache token counts, session identifier, timestamp, device host label, and the cost calculated by the server. The server trusts the authenticated ingest token—not a user ID or cost supplied by the event—to determine user attribution and pricing.
Users can set TOARD_HOST_LABEL to use a neutral device label or TOARD_DISABLE_HOST=1 to omit the host label. Host is display metadata, not part of the event deduplication key.
Event APIs use Authorization: Bearer <token>. Treat every ingest token as a user credential:
- issue and revoke tokens per user or device as appropriate;
- revoke a token after offboarding, a lost device, or suspected exposure;
- never put a token in logs, source control, tickets, or public documentation.
Use TLS for publicly reachable ingestion endpoints because the token travels in the authorization header. Content collection is stricter: the shim sends content only to https:// endpoints, except for local localhost or 127.0.0.1 development endpoints. A remote http:// endpoint is skipped for content collection.
AUTH_MODE selects the dashboard's OAuth/default mode or open viewing. Credentials sign-in is controlled separately by AUTH_CREDENTIALS_ENABLED. open permits unauthenticated dashboard viewing and is appropriate only for a trusted internal network. In open mode, the dashboard and settings pages can use the viewer fallback without a session, but token-management changes and all administration require a signed-in session. Ingestion always requires an ingest token regardless of dashboard mode.
Protect external /api/cron/* calls with CRON_SECRET. Without it, those endpoints are unauthenticated, so it must be set in production. The built-in pricing scheduler does not need an external caller in a normal self-hosted deployment.
Content collection is off by default. It requires both a server KEK and a user opt-in, for example TOARD_SHIM_COLLECT_CONTENT=1. When no KEK is configured, /api/v1/prompts returns 503 and the shim skips content collection.
On first enablement, the default collection boundary is “from now”; it does not send the user's historical conversations. An administrator can change the installation default with CONTENT_COLLECTION_DEFAULT=on, which turns the user experience into opt-out. Make that policy visible to affected users before enabling it.
Content records are envelope-encrypted at rest, and prompt_records uses owner-only row-level security (RLS). Those controls have important limits:
- RLS is enforced only when the application connects as a non-superuser role; a database superuser can bypass it.
- An operator who holds the KEK or has server-level access may be able to decrypt content.
- Losing the KEK makes existing encrypted content unreadable; retain it separately from database backups.
This is not end-to-end encryption. If that access model is unsuitable for your organization, leave content collection disabled. The deployment guide documents the required runtime role and key handling.
Do not open a public issue for a suspected vulnerability. Use GitHub Security Advisories and include the impact, reproduction steps, and affected version or commit where possible. The project's security policy lists the supported version and areas of interest.