Skip to main content

Encryption at Rest & in Transit

Data exists in two states: at rest (sitting on a disk somewhere) and in transit (travelling across a network between two machines). Both states need protection. Different kinds of protection.

This page explains how Dashify handles encryption in both states, where the boundaries are, and what is not encrypted (and why).

Encryption in transit

In transit means "moving over the network." Every connection in Dashify is encrypted with TLS, the protocol the browser shows as a padlock when you visit an HTTPS site.

Going through each link:

Browser to Edge. Always HTTPS in production. The HSTS header (covered on the Helmet page) makes sure even the first connection cannot fall back to HTTP.

Edge to API. In a typical deployment the reverse proxy or CDN terminates TLS at the edge and reaches the API over the internal network. If the internal network is not trusted (e.g., crossing data-centres), the edge-to-API link is also TLS or mutual TLS.

API to MongoDB. Managed MongoDB providers expose TLS endpoints by default. The connection string starts with mongodb+srv:// and includes tls=true. Self-hosted MongoDB requires explicit configuration, Dashify's setup guide insists on it for production.

API to Redis. Managed Redis providers expose rediss:// (TLS) endpoints. Self-hosted Redis can use TLS or be reachable only over a private network.

API to External services. SSO providers, Cloudinary, every outbound call uses HTTPS. The Node https module rejects expired or self-signed certificates by default, we do not loosen this.

There is no "internal traffic is fine in cleartext" exception. If a packet crosses any boundary outside a tightly-controlled local network, it is encrypted.

Encryption at rest

At rest means "stored on disk somewhere." Three categories of data, three approaches.

Database storage

MongoDB itself can be configured for encryption at rest at the storage engine layer. Atlas turns this on by default; self-hosted MongoDB requires --enableEncryption and a key file. The result is that the database files on the server's disk are encrypted with a master key, and someone who steals the disk image cannot read the data.

This is the baseline. Dashify expects it to be enabled in any production deployment.

Field-level encryption

A few fields are additionally encrypted at the application layer before they ever land in MongoDB. The platform encrypts:

  • 2FA secrets. Even if the database is breached, the attacker cannot reconstruct working TOTP codes without the encryption key.
  • SSO client secrets. The IdP credential a tenant entrusted to Dashify is encrypted before storage.
  • AI provider keys (when a tenant chooses to BYO an Anthropic API key). Encrypted before storage.

The encryption uses AES-256-GCM with a key sourced from the platform's environment (FIELD_ENCRYPTION_KEY). Rotating the key is a manual operation, rotate the key, decrypt-then-re-encrypt every affected document, then deploy. The platform exposes a script to do this safely.

Backup encryption

Backups inherit the same encryption-at-rest property as the live database. Atlas backups are encrypted on the storage layer. Self-hosted backups should be encrypted with mongodump --gzip plus an outer encryption layer (e.g., GPG with the operator's public key). The backup pipeline is operator-configured.

File uploads

User-uploaded files (avatars, attachments, knowledge base images) live on Cloudinary, not on Dashify's own infrastructure. Cloudinary handles encryption at rest, access tokens, signed URLs, and image transformations. Dashify stores only a reference (Cloudinary public_id and a few bits of metadata).

This delegates a hard problem (file storage at scale) to a specialist provider. The tradeoff is that we now trust Cloudinary's security posture as well as our own; that tradeoff is acceptable for the cost-and-complexity savings.

What is not encrypted (and why)

Some things in Dashify are not encrypted, deliberately.

  • Passwords are not stored encrypted. They are hashed with Argon2, covered on the Argon2 page. The distinction matters: hashed = irreversible (one-way); encrypted = reversible (with the key). Passwords should never be reversible.
  • Most database fields are not field-level encrypted. Encrypting every field would prevent indexing, querying, and filtering. The platform encrypts only the fields that have no need to be searchable and where the value is highly sensitive.
  • Logs and metrics are not field-level encrypted. They contain operational data, not secrets. The transport (TLS) and storage (encryption at rest on the log/metrics provider) protect them.

Key management

Encryption is only as strong as the keys. Dashify keeps keys in environment variables sourced from the deployment platform's secret manager (AWS Secrets Manager, Doppler, 1Password Secrets, etc.). Three rules apply:

  • Never check keys into git. The .env.example file in the repo lists the names of the keys, not the values.
  • Different environments, different keys. Production keys never appear in development. Development keys never reach production.
  • Rotation is supported. Every encryption key has a documented rotation procedure, even if the procedure is "regenerate, redeploy, re-encrypt."

TLS certificate considerations

In production, the proxy terminates TLS using a certificate issued by a trusted authority (Let's Encrypt is fine; commercial CAs are fine; the right answer depends on your hosting). The certificate is renewed automatically, typically every 60 days for Let's Encrypt, by the proxy itself.

A misconfigured certificate is one of the most common causes of "the site is down." The recommendation is to monitor the expiry date with a simple cron-like check and alert at 14 days remaining.

Future hardening

A few items on the roadmap that would tighten encryption:

  • Customer-managed encryption keys (BYOK). A large customer could provide their own root key for field-level encryption, so even Dashify's operators cannot read their secrets without their cooperation.
  • End-to-end encryption for chat. Currently chat messages are encrypted in transit and at rest, but readable by the platform. E2E would mean only the participants can decrypt them.
  • Hardware-Security-Module-backed signing keys. JWT and PAT signing keys could move into an HSM rather than living in environment variables.

These are real items in the gap list (covered in the Future section) and are realistic future work, not present today.

Key takeaways

  • In transit: every network connection uses TLS, browser to edge, edge to API, API to databases, API to external services.
  • At rest: MongoDB encrypts the storage layer; sensitive fields (2FA secrets, SSO secrets, AI keys) get additional field-level encryption with AES-256-GCM.
  • Passwords are hashed (Argon2), not encrypted, different concept, different purpose.
  • Files are stored on Cloudinary, which handles encryption and access control.
  • Keys live in the deployment's secret manager, never in git, never shared across environments.