Skip to content

Encryption Keys

Floh uses AES-256-GCM encryption for several categories of sensitive data. This document covers every key the application expects, how to generate them, and the procedures for rotating or migrating keys.


Key overview

Environment variable Purpose Required in production?
CONNECTOR_ENCRYPTION_KEY Encrypts connector secret fields at rest Yes
CONNECTOR_ENCRYPTION_KEY_PREVIOUS Allows decryption during key rotation No (rotation only)
SESSION_ENCRYPTION_KEY Encrypts OIDC access/refresh tokens in Redis Yes

Generating a key

All keys are 64-character hex strings (256 bits):

openssl rand -hex 32

CONNECTOR_ENCRYPTION_KEY

Used to encrypt secret fields in connector_definition.connector_config (fields marked secret: true in the connector's configSchema).

Development mode (NODE_ENV=development or test): if the variable is unset or invalid the application falls back to an insecure all-zeros key and logs a warning. This lets docker compose up work without any configuration.

Production (NODE_ENV=production): the application will not start if this key is missing or is not a valid 64-character hex string.

Key rotation

  1. Generate a new key: openssl rand -hex 32
  2. Set the old key as CONNECTOR_ENCRYPTION_KEY_PREVIOUS.
  3. Set the new key as CONNECTOR_ENCRYPTION_KEY.
  4. Restart the server. Reads will transparently fall back to the previous key if decryption with the new key fails.
  5. Call the admin endpoint to re-encrypt all connectors:
curl -X POST https://your-server/api/connectors/rotate-keys \
  -H "Authorization: Bearer <admin-token>"

The response includes a summary:

{ "total": 5, "rotated": 4, "skipped": 1, "failed": [] }

  1. Once all connectors are re-encrypted, remove CONNECTOR_ENCRYPTION_KEY_PREVIOUS and restart.

SESSION_ENCRYPTION_KEY

Used to encrypt session data (OIDC access and refresh tokens) before writing to Redis under floh:session:* keys.

Development mode: if unset, session data is stored as plaintext JSON in Redis.

Production: the application will not start without a valid key.

Rotation is not currently supported for session keys — sessions are short-lived (24h TTL) and will naturally expire under the old key. To rotate: set the new key and restart; all active sessions will be invalidated (users must re-authenticate).


Workflow & schedule variable encryption

Workflow variable definitions can include a secret: true flag. When set, the corresponding variable values are encrypted at rest in workflow_run.variables and scheduled_trigger.variables using the CONNECTOR_ENCRYPTION_KEY.

In API responses, secret variable values are replaced with ********. During workflow execution, secret values are decrypted for step evaluation and re-encrypted before persisting.

Adding a secret variable

In the workflow definition's variables array, set secret: true:

{
  "name": "apiKey",
  "type": "string",
  "required": true,
  "secret": true
}

Invitation token hashing

Invitation tokens (invitation_token.token) are stored as SHA-256 hashes rather than plaintext. No encryption key is needed — the tokens have sufficient entropy (32 random bytes) that a deterministic hash without salt is secure.

When an invitation link is opened, the raw token from the URL is hashed before looking it up in the database. A database compromise therefore does not directly expose valid invitation tokens.

Migration 030_hash_invitation_tokens converts existing plaintext tokens to hashes in place. This migration is irreversible.