How the Open Notebook Key Provider Falls Back from Database Credentials to Environment Variables

The Open Notebook key provider implements a database-first lookup strategy that automatically falls back to environment variables when credentials are missing, querying the Credential table before checking the PROVIDER_CONFIG mapping.

The lfnovo/open-notebook repository manages AI provider authentication through a resilient credential system that prioritizes secure database storage. Understanding how the key provider falls back from database credentials to environment variables ensures seamless operation when database records are unavailable or when integrating with libraries that expect standard environment-based API keys.

Database-First Lookup Strategy in key_provider.py

The core logic resides in open_notebook/ai/key_provider.py, where the _get_default_credential() helper function queries the Credential table for provider-specific records. According to the source code, this function searches for the first database record belonging to the requested provider (lines 77-84).

When a credential exists in the database, the function extracts the api_key field and returns the secret value directly (lines 98-101). This database-first approach ensures that user-configured keys stored in the application database take precedence over system environment variables.

The Environment Variable Fallback Mechanism

If the database query returns no results or the credential lacks an API key, the provider executes a fallback to environment variables. The mapping between providers and their canonical environment variable names is defined in the PROVIDER_CONFIG dictionary (lines 28-63).

For example, the "openai" provider maps to OPENAI_API_KEY, while other providers follow similar canonical naming conventions. The fallback logic checks this specific environment variable when no valid database credential is available (lines 102-108).

Complete Fallback Flow

The resolution follows this strict priority order:

  1. Query the Credential table for the provider using _get_default_credential()
  2. Return the stored api_key if found and valid
  3. Check the environment variable specified in PROVIDER_CONFIG for that provider
  4. Return None if neither source provides a key (lines 109-111)

Provisioning Keys at Runtime

The public get_api_key() coroutine encapsulates this fallback logic for higher-level consumption. Additionally, the module provides provisioning utilities that populate environment variables from database credentials before model instantiation.

Per-Provider Provisioning

The provision_provider_keys() function ensures specific provider credentials are loaded into the environment. This is critical when creating model instances that expect standard environment variables:

from open_notebook.ai.key_provider import provision_provider_keys

async def create_openai_model():
    await provision_provider_keys("openai")  # DB → env if present

    # Model factory now finds the key in environment

Global Startup Provisioning

For application initialization, provision_all_keys() iterates through all configured providers (lines 46-81). While useful for startup scripts, this approach is deprecated for per-request use in favor of targeted provisioning:

from open_notebook.ai.key_provider import provision_all_keys

async def startup():
    results = await provision_all_keys()
    print("Provisioning results:", results)

Integration with the Credential Domain Model

The fallback mechanism relies on open_notebook/domain/credential.py, which defines the Pydantic Credential model and the get_by_provider async query. The AI model factory in open_notebook/ai/model_factory.py consumes these keys, whether sourced directly from the database or inherited from environment variables populated by the provisioning functions.

Summary

  • The key provider in open_notebook/ai/key_provider.py prioritizes database credentials over environment variables
  • _get_default_credential() queries the Credential table first (lines 77-84)
  • Falls back to PROVIDER_CONFIG environment mappings when no database record exists (lines 102-108)
  • Returns None only when both database and environment sources fail (lines 109-111)
  • Use provision_provider_keys() to expose database credentials as environment variables for legacy model clients

Frequently Asked Questions

What happens if both the database and environment variable are missing?

The get_api_key() function returns None when neither the Credential table contains a record for the provider nor the corresponding environment variable is set in the system's PROVIDER_CONFIG mapping. This signals to calling code that no authentication is available for the requested AI provider.

Which takes precedence: database credentials or environment variables?

Database credentials always take precedence. The code explicitly checks the database first (lines 98-101) and only falls back to environment variables (lines 102-108) when no valid database credential exists. This ensures that application-specific configurations in the database override system-level environment settings.

How does the provider know which environment variable to check?

The PROVIDER_CONFIG mapping (lines 28-63) defines the canonical environment variable name for each provider. For example, the "openai" provider maps to OPENAI_API_KEY, ensuring consistent fallback behavior across different AI services without hardcoding variable names throughout the application.

Can I use database credentials without modifying environment variables?

Yes. The get_api_key() coroutine returns the database value directly without side effects on the environment. Only the provision_provider_keys() and provision_all_keys() functions explicitly populate environment variables to maintain compatibility with libraries that expect standard environment-based authentication.

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 →