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

> Learn how Open Notebook's key provider efficiently falls back from database credentials to environment variables. Discover the automatic lookup strategy for secure credential management.

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

---

**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`](https://github.com/lfnovo/open-notebook/blob/main/key_provider.py)

The core logic resides in [`open_notebook/ai/key_provider.py`](https://github.com/lfnovo/open-notebook/blob/main/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:

```python
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:

```python
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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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.