# How TREK Handles Encryption Key Rotation for Data Security

> Learn how TREK secures data with AES-256-GCM encryption and handles seamless encryption key rotation using a dedicated migration script without downtime. Ensure data integrity effortlessly.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: security
- Published: 2026-07-01

---

**TLDR:** TREK encrypts sensitive values at rest using AES-256-GCM and provides a dedicated migration script at [`scripts/migrate-encryption.ts`](https://github.com/mauriceboe/TREK/blob/main/scripts/migrate-encryption.ts) that re-encrypts all stored secrets without downtime, allowing seamless encryption key rotation while maintaining data integrity.

TREK, an open-source travel management application, protects sensitive configuration data such as API keys, OAuth secrets, and SMTP passwords using robust AES-256-GCM encryption. When security policies require periodic rotation or a potential compromise occurs, understanding the encryption key rotation process is essential for maintaining data confidentiality without service interruption.

## Key Resolution and Storage Architecture

TREK derives encryption keys using SHA-256 with a per-secret domain suffix, ensuring that the raw key is never stored directly in the database. According to the [`wiki/Encryption-Key-Rotation.md`](https://github.com/mauriceboe/TREK/blob/main/wiki/Encryption-Key-Rotation.md) documentation, the application resolves the encryption key through a specific priority chain on startup.

### Resolution Priority Order

The server checks for the encryption key in the following sequence, using the first source found:

1. **ENCRYPTION_KEY environment variable** – Highest priority. When set, the value is automatically persisted to `./data/.encryption_key` to ensure container restarts remain functional.
2. **./data/.encryption_key file** – The standard persistence location for installations that have started at least once.
3. **./data/.jwt_secret file** – Legacy fallback for older installations. The JWT secret is automatically copied to `./data/.encryption_key` on first start.
4. **Auto-generated 32-byte hex string** – For fresh installations with no existing key material.

## Performing Encryption Key Rotation

TREK implements a zero-downtime rotation strategy through the [`scripts/migrate-encryption.ts`](https://github.com/mauriceboe/TREK/blob/main/scripts/migrate-encryption.ts) script. This Node.js/TypeScript utility handles the cryptographic transition between keys without requiring manual database edits.

### Migration Script Workflow

The migration process follows these steps:

1. **Prerequisites**: The script creates a timestamped database backup named `travel.db.backup-<epoch>` before modifying any data.
2. **Interactive Prompting**: The script securely prompts for the **old** and **new** encryption keys (input is never echoed to the console).
3. **Re-encryption**: It iterates through every table containing encrypted values, decrypting with the old key and re-encrypting with the new key using AES-256-GCM.
4. **Atomic Updates**: Each row is rewritten with the newly encrypted ciphertext.
5. **Verification**: If any row fails to migrate, the script aborts immediately, returns a non-zero exit status, and leaves the original backup untouched.

### Running the Migration

Execute the script from the `server/` directory or within a Docker container:

```bash

# From host

cd server
node --import tsx scripts/migrate-encryption.ts

# From Docker container

docker exec -it trek node --import tsx scripts/migrate-encryption.ts

```

During execution, you will see interactive prompts:

```

Enter current ENCRYPTION_KEY:  ********
Enter new ENCRYPTION_KEY:      ********
Confirm re‑encryption? (y/N):

```

After successful completion, update the `ENCRYPTION_KEY` environment variable to the new value and restart the server.

## Backup and Security Considerations

Critical security notes regarding key management:

- **Separate Key Storage**: The regular backup ZIP does **not** contain the encryption key. You must store the key separately in a password manager or secrets vault.
- **Key Loss Implications**: If the encryption key is lost, all encrypted settings become unreadable and must be re-entered manually. Non-encrypted data (trips, users, places) remains accessible.
- **Environment Variable Persistence**: When using Docker, set the key via the environment variable in [`docker-compose.yml`](https://github.com/mauriceboe/TREK/blob/main/docker-compose.yml):

```yaml
services:
  trek:
    image: ghcr.io/mauriceboe/trek:latest
    environment:
      - ENCRYPTION_KEY=01ab23cd45ef6789...
    volumes:
      - trek-data:/app/data

```

## Legacy Installation Upgrades

Older TREK installations that used the JWT secret as the encryption source are automatically upgraded on first start. The system reads `./data/.jwt_secret`, copies it to `./data/.encryption_key`, and subsequent rotations use the new dedicated key file.

## Summary

- TREK uses **AES-256-GCM** for at-rest encryption of sensitive configuration values.
- Encryption keys are resolved via a priority chain: environment variable → `./data/.encryption_key` → legacy `./data/.jwt_secret` → auto-generated.
- The **[`scripts/migrate-encryption.ts`](https://github.com/mauriceboe/TREK/blob/main/scripts/migrate-encryption.ts)** script performs zero-downtime encryption key rotation by re-encrypting all secrets after prompting for old and new keys.
- Database backups are created automatically before rotation (`travel.db.backup-<epoch>`), but the encryption key itself is **never** included in application backups and must be stored separately.
- Legacy installations automatically migrate to the dedicated encryption key file on first startup.

## Frequently Asked Questions

### What happens if I lose the encryption key?

All encrypted settings become permanently unreadable and must be re-entered manually through the UI. Non-encrypted data such as trips, users, and places remains intact and accessible. There is no recovery mechanism for encrypted data without the original key.

### Does the migration script require downtime?

No. The [`scripts/migrate-encryption.ts`](https://github.com/mauriceboe/TREK/blob/main/scripts/migrate-encryption.ts) script performs the rotation while the application is running. However, you should update the `ENCRYPTION_KEY` environment variable and restart the server immediately after successful completion to ensure consistency.

### How do I verify which encryption key is currently active?

Check the `./data/.encryption_key` file on the host filesystem, or inspect the `ENCRYPTION_KEY` environment variable if set. The application logs the key resolution source during startup according to the priority order defined in [`wiki/Encryption-Key-Rotation.md`](https://github.com/mauriceboe/TREK/blob/main/wiki/Encryption-Key-Rotation.md).

### Can I rotate keys if I only have the old ENCRYPTION_KEY environment variable?

Yes. The migration script prompts interactively for both the old and new keys. As long as you possess the current valid key (regardless of whether it originated from an environment variable, file, or legacy JWT secret), you can execute the rotation and then transition to a new key file or environment variable configuration.