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 32Channel 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.
Authentication
Sign up, SSO login, password rules, email verification, TOTP two-factor authentication with backup codes, project-wide 2FA enforcement, and invite-only mode for self-hosted Alphorn.
API Reference
Alphorn HTTP API for sending notifications - endpoint, Bearer API key authentication, JSON, Slack-compatible and plain-text payloads, status codes, and code examples.