AlphornAlphorn Docs

Privacy & Security

How Alphorn handles your data: TLS encryption, webhook API key security, authentication, channel credential storage, project isolation, and disclosure.

Data handling

What Alphorn stores

  • Notification payloads - title, message, priority, tags, and custom payload data
  • Delivery logs - per channel: status, number of attempts, the last error message, and when it was delivered
  • Channel configuration - webhook URLs, API keys, and credentials for your notification channels
  • Account data - name, email address, project memberships, password hash, 2FA secret and backup codes (encrypted with BETTER_AUTH_SECRET), and, for SSO logins, the tokens issued by the identity provider (not encrypted separately)
  • Sessions - IP address and browser user agent of each login session

What Alphorn doesn't do

  • Alphorn does not sell or share your data with third parties
  • Alphorn does not use your notification content for training, analytics, or advertising
  • Alphorn does not track you across websites or services

Self-hosted: you control everything

When you self-host Alphorn, all data stays in your PostgreSQL database on your infrastructure. Nothing is sent to Alphorn's servers. You have full control over backups and access. Note that self-hosted instances have no automatic message retention: messages and delivery logs are kept indefinitely.

Encryption

In transit

All communication with the hosted service at app.alphorn.dev uses TLS (HTTPS).

For self-hosted instances, configure TLS through your reverse proxy (Nginx, Caddy, Traefik). Caddy enables HTTPS automatically. See Self-Hosting → Reverse Proxy & HTTPS for an Nginx example with the headers Alphorn needs.

At rest

Database encryption depends on your PostgreSQL configuration and hosting provider. Most managed PostgreSQL providers (AWS RDS, Supabase, Neon, etc.) encrypt data at rest by default. For self-managed PostgreSQL, configure disk encryption at the OS level.

Webhook security

Webhook API keys

Each webhook URL contains a random, unguessable 21-character ID (e.g., /n/V1StGXR8_Z5jdHi6B-myT). On top of that, you can switch on Require API key per webhook (off by default), so every request must send Authorization: Bearer <api-key>:

  • Keys are 256-bit random values (alp_ + 64 hex characters)
  • Alphorn stores only a SHA-256 hash of each key - a database dump does not reveal usable keys
  • The full key is shown once, when the webhook is created or the key is regenerated
  • Keys are compared in constant time

If you create a webhook without an API key, the URL itself is the only secret: anyone with the URL can send notifications to that webhook. Only do this for tools that can't send custom headers.

Treat API keys and webhook URLs like passwords:

  • Don't commit them to public repositories
  • Don't log them in plain text
  • Use environment variables or secrets management in CI/CD
  • If a key or URL has been exposed, use Regenerate key or Regenerate URL on the webhook page - the old one stops working immediately (behind a PgBouncer in transaction mode, within 30 seconds)

Stream URLs

Live Stream URLs are not protected by an API key. Anyone who knows a stream URL can read the notifications sent to that channel, so keep them private. Stream URLs can't be regenerated - if one leaks, delete the channel and create a new one.

IP restrictions

For self-hosted instances, you can restrict webhook access at the network level using your reverse proxy or firewall to only accept requests from known source IPs.

Authentication security

Passwords

Alphorn uses Better Auth for authentication. Passwords are hashed with scrypt before storage.

Two-factor authentication

Alphorn supports TOTP-based 2FA with backup codes. Project owners and admins can require 2FA for all members. See Authentication for setup instructions.

SSO

Alphorn supports GitHub, Google, Microsoft, and any OIDC-compliant identity provider. SSO tokens are managed by Better Auth and stored server-side. See Authentication for details.

Session management

Sessions are stored in the database and their cookies are signed with BETTER_AUTH_SECRET. Use a strong, random secret - generate one with:

openssl rand -base64 32

Channel credentials

Channel configuration (Slack webhook URLs, API keys, SMTP passwords, etc.) is stored in PostgreSQL in plain text - Alphorn does not encrypt it separately. Only admins and owners can see channel details in the dashboard. Error messages from channels (up to 500 characters of the provider's response) are stored in the delivery log. For self-hosted instances, secure your database and its backups:

  • Use strong PostgreSQL passwords
  • Restrict database access to the Alphorn application only
  • Use SSL connections to PostgreSQL in production
  • Back up your database with encryption

Project isolation

Each project is fully isolated:

  • Webhooks, channels, and filtering rules are scoped to the project
  • Members can only access their own projects
  • Role-based access control limits who can manage configuration vs. view logs

Responsible disclosure

If you find a security vulnerability in Alphorn, please report it privately by email to hello@alphorn.dev rather than opening a public issue. See SECURITY.md for details.

On this page