# Where Is the Encryption Key for Securing API Credentials Stored in SurrealDB?

> Discover where SurrealDB stores encryption keys for API credentials. Learn it's not in the database but supplied at runtime via environment variables or Docker secrets for enhanced security.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-07-04

---

**The encryption key for securing API credentials is not stored inside SurrealDB; instead, it is supplied at runtime via the `OPEN_NOTEBOOK_ENCRYPTION_KEY` environment variable or a Docker secret file, while only encrypted Fernet tokens persist in the database.**

Open Notebook manages sensitive API credentials by keeping the encryption key entirely outside the database. In the `lfnovo/open-notebook` repository, the system uses an environment-based secret to encrypt credentials before they ever touch SurrealDB. This architecture ensures that even if the database is compromised, the API keys remain unreadable without the external encryption key.

## How the Encryption Key Is Managed Outside SurrealDB

The encryption key is never written to the `credential` table or any other SurrealDB collection. According to the source code in [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py), the application retrieves the secret from the process environment at runtime using the `get_secret_from_env` utility.

### Environment Variable and Docker Secret Configuration

The system checks for the `OPEN_NOTEBOOK_ENCRYPTION_KEY` environment variable. It also supports Docker secrets by looking for a file path specified in `OPEN_NOTEBOOK_ENCRYPTION_KEY_FILE`. As implemented in [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py) (lines 62-79), the utility reads the value directly from the environment or from the referenced file, ensuring the key lives only in memory and never touches the disk in plain text within the database directory.

## Where Encrypted Credentials Live in SurrealDB

While the encryption key remains external, the encrypted API credentials themselves are stored in the **`credential`** table of SurrealDB. The `api_key` column contains Fernet-encrypted tokens rather than plain text.

### The Credential Domain Model

In [`open_notebook/domain/credential.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/credential.py) (lines 4-6), the `Credential` model defines the structure for stored credentials. When a record is saved, the plain-text API key is encrypted using `encrypt_value()` before insertion. When retrieving records (lines 55-69), the application calls `decrypt_value()` to restore the original API key in memory, leaving the database copy encrypted.

## Validating and Using the Encryption Key

Before any credential operations occur, the application validates that the encryption key is properly configured.

### Startup Validation in the Credentials Service

The `require_encryption_key` function in [`api/credentials_service.py`](https://github.com/lfnovo/open-notebook/blob/main/api/credentials_service.py) (lines 199-204) acts as a guard. It calls `get_secret_from_env("OPEN_NOTEBOOK_ENCRYPTION_KEY")` and raises a `ValueError` if the key is missing. This guarantees that any write operation, such as `POST /credentials`, fails fast when the encryption environment is not configured.

### Encryption and Decryption Functions

The [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py) module provides the core cryptography functions. The `encrypt_value()` function generates a Fernet token from the plain-text input, while `decrypt_value()` reverses the process using the same runtime-derived key. These functions ensure that only encrypted data traverses the network to SurrealDB.

## Practical Implementation Example

The following examples demonstrate how the encryption key is used to secure API credentials before they reach SurrealDB.

First, configure the encryption key in your environment:

```bash

# .env file or Docker secret

OPEN_NOTEBOOK_ENCRYPTION_KEY=my-super-secret-passphrase

```

Then, encrypt values before storage and decrypt them on retrieval:

```python
from open_notebook.utils.encryption import encrypt_value, decrypt_value

# Encrypt before storing in SurrealDB

plain_api_key = "sk-abc123"
encrypted_token = encrypt_value(plain_api_key)

# encrypted_token is now stored in credential.api_key

# Decrypt when reading from SurrealDB

decrypted_key = decrypt_value(encrypted_token)

# Returns: "sk-abc123"

```

When the application starts, the `require_encryption_key()` guard ensures the `OPEN_NOTEBOOK_ENCRYPTION_KEY` is present; otherwise, it raises a clear error to prevent unsecured credential storage.

## Summary

- **The encryption key is external**: Open Notebook stores the `OPEN_NOTEBOOK_ENCRYPTION_KEY` only in the environment or a Docker secret file, never in SurrealDB.
- **Encrypted tokens persist**: The `credential` table holds Fernet-encrypted values in the `api_key` column, not plain text.
- **Validation is strict**: The `require_encryption_key` function in [`api/credentials_service.py`](https://github.com/lfnovo/open-notebook/blob/main/api/credentials_service.py) prevents any credential operations if the encryption key is missing.
- **Memory-only decryption**: The `Credential` model in [`open_notebook/domain/credential.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/credential.py) decrypts values only when loaded into memory, keeping the database copy secure.

## Frequently Asked Questions

### Does Open Notebook store the encryption key in SurrealDB?

No. The encryption key is explicitly kept outside of SurrealDB. It is provided via the `OPEN_NOTEBOOK_ENCRYPTION_KEY` environment variable or a Docker secret file referenced by `OPEN_NOTEBOOK_ENCRYPTION_KEY_FILE`. The database only stores encrypted Fernet tokens produced by the `encrypt_value()` function.

### What happens if the encryption key is missing when the application starts?

The application will raise a `ValueError` immediately. The `require_encryption_key` function in [`api/credentials_service.py`](https://github.com/lfnovo/open-notebook/blob/main/api/credentials_service.py) (lines 199-204) validates the presence of the key before any credential write operations, causing a fast failure that prevents unsecured storage.

### Which SurrealDB table stores the encrypted API credentials?

Encrypted API credentials are stored in the **`credential`** table. Specifically, the `api_key` column contains the encrypted Fernet tokens, while the encryption key remains in the runtime environment.

### How does the Credential model decrypt values when reading from the database?

The `Credential` model in [`open_notebook/domain/credential.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/credential.py) (lines 55-69) calls `decrypt_value()` after loading a record from SurrealDB. This function uses the same `OPEN_NOTEBOOK_ENCRYPTION_KEY` from the environment to decrypt the token, returning the plain-text API key only in memory while leaving the database copy encrypted.