How to Configure AI Provider Credentials in the Database Instead of Environment Variables

Open Notebook stores AI provider authentication data in SurrealDB's credential table, automatically decrypting and injecting these secrets into environment variables at runtime to override static env-var configurations.

Open Notebook provides a flexible, database-first approach to managing AI provider credentials. Rather than relying solely on static environment variables, you can configure AI provider credentials in the database, enabling runtime updates without service restarts while maintaining backward compatibility with existing env-var setups.

Understanding the Database-First Credential Architecture

Open Notebook uses SurrealDB as the backing store for credential management, implementing a secure encryption layer and a runtime injection system. When a model is provisioned, the system queries the database first, decrypts the stored secrets, and populates the appropriate environment variables dynamically.

This architecture ensures that database-stored credentials take precedence over environment variables, while still allowing legacy env-var configurations to function as fallbacks.

The Credential Model and Encryption

The Credential model in open_notebook/domain/credential.py defines the schema for storing provider authentication data. Before saving, the _prepare_save_data method encrypts the api_key field to ensure secrets are never stored in plaintext. The model also includes a flexible config object (added in Migration 15) that preserves provider-specific settings such as num_ctx, base_url, or custom endpoints.

Key fields include:

  • provider – The AI provider name (e.g., openai, azure_openai, ollama)
  • api_key – Encrypted secret key
  • modalities – Supported model types (language, embedding, image)
  • base_url – Custom endpoint URL for self-hosted providers

The Key Provider Module

The open_notebook/ai/key_provider.py module handles runtime credential resolution. The provision_provider_keys function retrieves the default credential for a specified provider and injects the decrypted values into os.environ using provider-specific variable names defined in PROVIDER_CONFIG.

Storing Credentials in SurrealDB

You can populate the credential table either through the REST API or directly via Python code. Both methods automatically encrypt sensitive data before persistence.

Using the Credentials API

The Credentials API router (api/routers/credentials.py) exposes CRUD endpoints for managing credentials. Create a new credential by POSTing to the credentials endpoint:

curl -X POST http://localhost:5055/credentials \
  -H "Content-Type: application/json" \
  -d '{
        "name": "OpenAI Production",
        "provider": "openai",
        "modalities": ["language", "embedding"],
        "api_key": "sk-REDACTED",
        "config": {"num_ctx": 16384}
      }'

Programmatic Credential Creation

For self-hosted providers like Ollama, you can create credentials directly in Python:

from open_notebook.domain.credential import Credential

await Credential(
    name="Local Ollama",
    provider="ollama",
    api_key="dummy",            # Ollama may not require a key

    base_url="http://localhost:11434"
).save()

Runtime Loading and Environment Variable Injection

When provisioning models, Open Notebook automatically loads database credentials before initializing the AI client. This process ensures that any runtime updates to the credential table are immediately available without restarting the service.

How provision_provider_keys Works

The workflow occurs in open_notebook/ai/models.py when AIFactory.create_language() is invoked:

  1. provision_provider_keys calls _get_default_credential internally
  2. _get_default_credential executes SELECT * FROM credential WHERE provider = $provider via Credential.get_by_provider
  3. Decryption – The decrypt_value method decrypts the stored API key
  4. Injection – The key and configuration are written to os.environ (e.g., OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT)

Provider-Specific Configuration Mapping

The PROVIDER_CONFIG dictionary maps provider names to their corresponding environment variable names. When provisioning, the system copies not only the api_key but also provider-specific fields like base_url, endpoint, or project into the appropriate env vars.

from open_notebook.ai.key_provider import provision_provider_keys
from esperanto import AIFactory

# Load DB-stored OpenAI credentials into env vars

await provision_provider_keys("openai")

# Create model using the dynamically loaded credentials

model = AIFactory.create_language(model_name="gpt-4", provider="openai")

Reading Credentials for Custom Logic

If you need to access credentials directly for custom implementations, use the Credential domain model:

from open_notebook.domain.credential import Credential

# Get all stored OpenAI credentials

openai_creds = await Credential.get_by_provider("openai")
for cred in openai_creds:
    print(cred.name, cred.api_key.get_secret_value())

Summary

  • Database-First Approach: Open Notebook queries SurrealDB's credential table before checking environment variables, allowing runtime credential updates without service restarts.
  • Automatic Encryption: The Credential model in open_notebook/domain/credential.py encrypts API keys via _prepare_save_data before storage.
  • Runtime Injection: The provision_provider_keys function in open_notebook/ai/key_provider.py decrypts credentials and injects them into os.environ during model provisioning.
  • Flexible Configuration: The config field supports provider-specific settings like base_url, num_ctx, and custom endpoints.
  • Backward Compatibility: If no database credential exists, the system falls back to existing environment variables.

Frequently Asked Questions

How are API keys secured when stored in the database?

API keys are encrypted before storage using the _prepare_save_data method in the Credential model. When retrieved, the decrypt_value method decrypts the secret only at runtime, ensuring plaintext keys never persist in the database.

Can I use multiple credentials for the same provider?

Yes, the Credential.get_by_provider method returns all credentials for a given provider. However, _get_default_credential selects the first matching record, so the system typically uses the earliest created credential unless you implement custom selection logic.

What happens if no credential exists in the database?

If provision_provider_keys finds no matching credential in SurrealDB, the function exits without modifying environment variables. The application then relies on existing environment variables (e.g., OPENAI_API_KEY), maintaining backward compatibility with traditional configuration methods.

Which environment variables are set when provisioning credentials?

The specific variables depend on the provider configuration. For OpenAI, the system sets OPENAI_API_KEY. For Azure OpenAI, it sets AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT, and related project fields. Self-hosted providers like Ollama receive OLLAMA_API_BASE mapped from the base_url field.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →