Encryption
How HelloJohn encrypts data at rest and in transit — field-level encryption, TLS, password hashing, and self-hosted recommendations.
Encryption
HelloJohn protects sensitive data through multiple encryption layers: TLS for data in transit, field-level encryption for secrets, and bcrypt/Argon2 for passwords. This page describes exactly what is encrypted and how.
Data in Transit
All communication between clients and HelloJohn uses TLS 1.2+. TLS 1.3 is preferred and enforced when both parties support it.
| Connection | Encryption |
|---|---|
| Browser → HelloJohn API | TLS 1.3 (HTTPS) |
| Your backend → HelloJohn API | TLS 1.3 (HTTPS) |
| HelloJohn → your webhook endpoint | TLS 1.2+ (HTTPS) |
| HelloJohn → email provider (SMTP) | STARTTLS or TLS |
| HelloJohn → PostgreSQL | TLS (configurable) |
| HelloJohn → Redis | TLS (configurable) |
HTTP requests are automatically redirected to HTTPS. Plain HTTP is not accepted on any production endpoint.
Password Hashing
HelloJohn never stores passwords in plaintext or reversibly encrypted form. Passwords are hashed using Argon2id (memory-hard, resistant to GPU and side-channel attacks):
| Parameter | Value |
|---|---|
| Algorithm | Argon2id |
| Memory cost | 64 MB |
| Iterations | 3 |
| Parallelism | 4 |
| Output length | 32 bytes |
Older deployments using bcrypt (cost factor 12) are migrated to Argon2id on next password change.
Passwords are never logged, included in error messages, or transmitted to third parties.
Sensitive Field Encryption
Certain fields are encrypted at the application layer before writing to the database, using AES-256-GCM:
| Field | Encrypted |
|---|---|
| OAuth client secrets (provider credentials) | ✅ Yes |
| SMTP passwords | ✅ Yes |
| TOTP backup codes | ✅ Yes |
| Webhook signing secrets | ✅ Yes |
| Refresh tokens (stored value) | ✅ Yes — hashed (SHA-256) |
| User emails | ⬜ No — stored plaintext, searchable |
| User names | ⬜ No |
| Session metadata | ⬜ No |
The encryption key is derived from HELLOJOHN_ENCRYPTION_KEY. If this key is rotated, all encrypted fields must be re-encrypted (see Key Rotation).
JWT Signing
Access tokens and refresh tokens are signed with Ed25519 (EdDSA). Signing is not encryption — tokens are Base64-encoded and readable, but cannot be forged without the private key.
Tokens do not contain passwords, secrets, or sensitive PII beyond the user ID and claims you configure.
See JWT Security for full details.
Database Encryption
Cloud-Hosted (HelloJohn-managed)
HelloJohn's managed infrastructure uses AES-256 encryption at rest on all storage volumes, managed by the cloud provider (AWS EBS, GCP PD).
Self-Hosted Recommendations
For self-hosted deployments, enable PostgreSQL column-level encryption or full-disk encryption:
Option 1: Full-disk encryption (Linux)
# Using dm-crypt / LUKS (set up at provisioning time)
cryptsetup luksFormat /dev/sdb
cryptsetup open /dev/sdb pg_data
mkfs.ext4 /dev/mapper/pg_dataOption 2: PostgreSQL TDE (Transparent Data Encryption)
Available on PostgreSQL Enterprise and some forks (Percona, EDB). Standard community PostgreSQL does not include native TDE.
Option 3: Managed database with encryption at rest
Use a managed PostgreSQL provider that encrypts at rest by default:
| Provider | Encryption at rest |
|---|---|
| Neon | AES-256 (AWS) |
| Supabase | AES-256 (AWS) |
| Amazon RDS | AES-256 (optional, enable in settings) |
| Google Cloud SQL | AES-256 |
For Amazon RDS, enable encryption at creation:
aws rds create-db-instance \
--db-instance-identifier hellojohn-db \
--storage-encrypted \
--kms-key-id arn:aws:kms:us-east-1:123456789:key/your-key-id \
# ... other optionsEncryption Key Rotation
Application Encryption Key
The HELLOJOHN_ENCRYPTION_KEY encrypts sensitive fields (OAuth secrets, SMTP passwords, backup codes, webhook secrets).
To rotate:
-
Generate a new 32-byte key:
openssl rand -base64 32 -
Set both the old and new key in the environment:
HELLOJOHN_ENCRYPTION_KEY=new_key_base64 HELLOJOHN_ENCRYPTION_KEY_PREVIOUS=old_key_base64 -
Run the key rotation migration:
hj admin rotate-encryption-key -
After migration completes, remove
HELLOJOHN_ENCRYPTION_KEY_PREVIOUS.
HelloJohn re-encrypts all sensitive fields using the new key. During the rotation window, both keys are accepted for reads.
JWT Signing Key
See Key Rotation for JWT signing key rotation procedure.
Backup Encryption
Encrypt database backups before storing off-site:
# Encrypt backup with GPG
pg_dump --format=custom --compress=9 --dbname="$DATABASE_URL" \
| gpg --symmetric --cipher-algo AES256 \
> hellojohn_$(date +%Y%m%d).dump.gpg
# Decrypt to restore
gpg --decrypt hellojohn_20240120.dump.gpg \
| pg_restore --dbname="$RESTORE_DATABASE_URL"Or use S3 server-side encryption:
aws s3 cp hellojohn.dump \
s3://your-backup-bucket/hellojohn.dump \
--sse aws:kms \
--sse-kms-key-id arn:aws:kms:us-east-1:123456789:key/your-key-idWhat Is Not Encrypted
For performance and searchability, some fields are stored in plaintext:
- User email addresses (required for lookups and matching)
- User display names
- Session metadata (IP addresses, user agents — unless you disable collection)
- Audit log entries
If your compliance requirements mandate encrypting user emails, use the Backend Proxy Pattern so HelloJohn never receives raw emails — only your system does.