Tymeslot encrypts sensitive integration credentials at rest using AES-256-GCM. This applies to every piece of secret material that leaves the user’s browser and is stored in the database: OAuth tokens for Google Calendar and Outlook, CalDAV passwords, video conferencing API keys (Google Meet, Microsoft Teams), Slack and Telegram bot tokens, and webhook signing secrets.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Tymeslot/tymeslot/llms.txt
Use this file to discover all available pages before exploring further.
What is encrypted
The following credential types are encrypted before being written to the database:- Google Calendar and Outlook OAuth access and refresh tokens
- CalDAV server passwords (Nextcloud, Radicale, Zimbra, mailbox.org)
- Video conferencing API keys and OAuth tokens
- Slack Incoming Webhook URLs and OAuth tokens
- Telegram bot tokens and chat IDs
- Outbound webhook signing secrets
Default behaviour and its drawback
WhenDATA_ENCRYPTION_KEY is not set, Tymeslot derives the AES-256-GCM encryption key from SECRET_KEY_BASE. This works, but it welds two concerns together: the cookie-signing secret and the data-at-rest protection key are the same material.
The consequence is that rotating SECRET_KEY_BASE — for example, after a suspected token leak — would make every stored credential undecryptable, because the derived encryption key would change. Every user would need to reconnect every integration.
A startup warning is logged whenever the application starts without DATA_ENCRYPTION_KEY set:
Setting DATA_ENCRYPTION_KEY
DATA_ENCRYPTION_KEY is an optional but strongly recommended environment variable that provides a dedicated encryption key, independent of SECRET_KEY_BASE. Once set, the two secrets are fully decoupled: you can rotate SECRET_KEY_BASE freely without affecting stored credentials.
Generate a high-entropy key with:
.env:
Enabling it on an existing install
If you are addingDATA_ENCRYPTION_KEY to an instance that already has stored credentials, follow these three steps. Skipping the re-encryption sweep leaves existing credentials encrypted under the old (derived) key — they still decrypt correctly, but SECRET_KEY_BASE remains coupled to the data until the sweep runs.
Generate the key and add it to your environment
.env to your secrets store before proceeding.Restart the container
Run the re-encryption sweep
Migrate all existing credentials onto the new key by running:The command prints a summary including a The sweep is idempotent — it is safe to run it multiple times. Credentials already on the current key are skipped.
migrated_values count. Re-run the sweep until migrated_values reaches 0, confirming that every stored credential is now encrypted under DATA_ENCRYPTION_KEY:migrated_values: 0 is it safe to rotate SECRET_KEY_BASE without disrupting stored integrations.
Key rotation
The encryption format is versioned, which means it is built for key rotation, not just the one-time migration described above. When a new key version is introduced in a future release, it gets its own version tag and coexists with the existing key: new writes use the new key, existing values continue opening under the previous key, and a re-encryption sweep walks the entire dataset onto the new key. Only once the sweep reports zero migrated values is the previous key retired. No credential is ever silently lost during this process.Summary
| Scenario | Action |
|---|---|
| Fresh install | Generate DATA_ENCRYPTION_KEY before first start |
Existing install without DATA_ENCRYPTION_KEY | Add key, restart, run sweep |
Rotate SECRET_KEY_BASE | Must complete sweep first (if DATA_ENCRYPTION_KEY not yet set) |
Lost DATA_ENCRYPTION_KEY | Stored credentials are unrecoverable; users must reconnect integrations |