How the key_provider Module Implements Database-First API Key Fallback Logic
The key_provider module in lfnovo/open-notebook implements a database-first retrieval strategy that checks the Credential store before falling back to environment variables, ensuring persisted secrets take precedence over system configuration.
The open_notebook.ai.key_provider module serves as the centralized credential broker for the Open Notebook application. Located in open_notebook/ai/key_provider.py, this utility translates database-stored secrets into the environment variables expected by AI SDKs. By prioritizing the database over environment variables, the module ensures that user-configured credentials always override system defaults.
Provider-to-Environment Variable Mapping
The foundation of the fallback system relies on a static configuration dictionary that maps provider names to their expected environment variable names.
The PROVIDER_CONFIG Dictionary
At line 28 of open_notebook/ai/key_provider.py, the PROVIDER_CONFIG dictionary defines the exact environment variable name that each AI provider's SDK expects:
# Simplified representation of the mapping structure
PROVIDER_CONFIG = {
"openai": "OPENAI_API_KEY",
"anthropic": "ANTHROPIC_API_KEY",
# ... additional providers
}
This mapping ensures that when the module retrieves credentials from the database, it knows precisely which environment variable to populate for each provider.
Database-First Retrieval Logic
The core retrieval flow follows a strict hierarchy: database credentials take precedence, with environment variables serving only as a fallback mechanism.
Querying the Default Credential
The private helper _get_default_credential() (line 76) queries the Credential domain model for the first record matching a given provider name. This function interacts with open_notebook/domain/credential.py to fetch the stored secret records.
API Key Extraction with Environment Fallback
The get_api_key() function (line 87) implements the dual-source lookup logic:
- Database Priority: The function first checks if a credential exists and contains an
api_keyfield. If found, it returns the secret afterpydantic.SecretStr-style deserialization. - Environment Fallback: If no credential exists or the credential lacks an
api_key, the function falls back to reading the environment variable defined inPROVIDER_CONFIG(line 100).
# Example 1 – Retrieve a single API key (database‑first)
from open_notebook.ai.key_provider import get_api_key
# Asynchronously obtain the OpenAI key; falls back to OPENAI_API_KEY env var
api_key = await get_api_key("openai")
print("OpenAI key:", api_key)
Provider Provisioning Strategies
The module distinguishes between simple providers that only require an API key and complex providers needing additional configuration parameters.
Simple Provider Provisioning
For providers requiring only an API key, _provision_simple_provider() (line 124) mirrors the database-first logic:
- Loads the credential using
_get_default_credential() - Writes the API key to the mapped environment variable from
PROVIDER_CONFIG - Copies any
base_urlinto a provider-specific<PROVIDER>_API_BASEvariable
Complex Provider Configurations
Complex providers such as Vertex AI, Azure OpenAI, and generic OpenAI-compatible endpoints have dedicated provisioning functions that handle multiple configuration fields:
_provision_vertex()(line 145): Extracts project, location, and credential path from the database record._provision_azure()(line 174): Handles Azure-specific endpoints and authentication parameters._provision_openai_compatible()(line 221): Manages custom base URLs and authentication for compatible endpoints.
Each function pulls relevant fields from the credential record and injects them into the appropriate environment variables expected by the respective SDKs.
Public API Interface
The module exposes two primary entry points for credential provisioning.
Per-Provider Provisioning
The provision_provider_keys() function (line 118) normalizes the provider name, selects the correct provisioning routine (simple or complex), and returns True when any variable was set from the database.
# Example 2 – Provision environment variables for a provider before model creation
from open_notebook.ai.key_provider import provision_provider_keys
await provision_provider_keys("azure") # Loads Azure credentials into env
# Now any Azure‑OpenAI SDK call will see AZURE_OPENAI_API_KEY, etc.
Bulk Key Provisioning
The provision_all_keys() function (line 83) walks the entire PROVIDER_CONFIG dictionary and runs per-provider provisioning for all entries. It returns a dictionary recording which providers were populated from the database versus environment variables.
# Example 3 – Bulk provisioning at application startup (not recommended per‑request)
from open_notebook.ai.key_provider import provision_all_keys
results = await provision_all_keys()
print("Provisioning results:", results)
# → {'openai': True, 'anthropic': False, ...}
Note: As implemented in the source code, this bulk operation is deprecated for request-time use and intended primarily for application initialization.
Summary
- The
key_providermodule uses a staticPROVIDER_CONFIGdictionary (line 28) to map provider names to their expected environment variable names. get_api_key()(line 87) implements a database-first lookup that only falls back to environment variables when no credential exists in the database._provision_simple_provider()(line 124) handles basic API key injection, while dedicated functions like_provision_azure()(line 174) manage complex multi-field configurations.- The public entry point
provision_provider_keys()(line 118) normalizes provider names and coordinates the appropriate provisioning strategy. provision_all_keys()(line 83) provides bulk provisioning capabilities but is deprecated for per-request usage to avoid unnecessary database queries.
Frequently Asked Questions
How does the key_provider module prioritize credential sources?
The module follows a strict database-first hierarchy: it queries the Credential model via _get_default_credential() before checking environment variables. This ensures that user-configured credentials in the database always override system environment variables, with the fallback only activating when no database record exists.
What happens if no credential exists in the database?
When _get_default_credential() returns None or the credential lacks an api_key field, get_api_key() (line 100) automatically falls back to reading the environment variable defined in PROVIDER_CONFIG. If neither source yields a key, the function returns None.
Which providers require complex provisioning logic?
While simple providers like OpenAI and Anthropic use _provision_simple_provider(), complex providers including Vertex AI, Azure OpenAI, and generic OpenAI-compatible endpoints require specialized functions. These handle additional fields such as project IDs, locations, Azure endpoints, and custom base URLs that must be injected into specific environment variables.
Is provision_all_keys() suitable for per-request use?
No. According to the source implementation in open_notebook/ai/key_provider.py, provision_all_keys() (line 83) is deprecated for request-time use because it queries the database for every configured provider. Instead, use provision_provider_keys() to target only the specific provider needed for the current request, minimizing database load and improving response times.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →