# How the key_provider Module Implements Database-First API Key Fallback Logic

> Discover how the key_provider module uses database-first API key fallback logic, prioritizing persisted secrets over environment variables for robust security in open-notebook.

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

---

**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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/key_provider.py), the `PROVIDER_CONFIG` dictionary defines the exact environment variable name that each AI provider's SDK expects:

```python

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

1. **Database Priority**: The function first checks if a credential exists and contains an `api_key` field. If found, it returns the secret after `pydantic.SecretStr`-style deserialization.
2. **Environment Fallback**: If no credential exists or the credential lacks an `api_key`, the function falls back to reading the environment variable defined in `PROVIDER_CONFIG` (line 100).

```python

# 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_url` into a provider-specific `<PROVIDER>_API_BASE` variable

### 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.

```python

# 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.

```python

# 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_provider` module uses a **static `PROVIDER_CONFIG` dictionary** (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`](https://github.com/lfnovo/open-notebook/blob/main/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.