How to Integrate Credential Management with Key Provider for API Key Lookup in Open Notebook

Open Notebook integrates credential management with the key provider by storing encrypted API keys in the Credential domain model and injecting them into the process environment at runtime via the key provider module, enabling secure AI provider authentication.

Open Notebook solves the challenge of securely managing AI provider credentials by combining a database-backed credential store with a runtime key provisioning system. When you integrate credential management with the key provider for API key lookup, encrypted secrets are retrieved from SurrealDB and mapped to environment variables that the underlying Esperanto AI library expects. This architecture ensures that sensitive API keys remain encrypted at rest while remaining accessible to the models that need them.

Understanding the Architecture

The Credential Domain Model

Located in open_notebook/domain/credential.py, the Credential class persists provider-specific secrets in SurrealDB. Each record stores the provider name, encrypted API key, and optional configuration fields such as base_url or endpoint. The model automatically encrypts the api_key field on save via _prepare_save_data and decrypts it on read using get_secret_value(), ensuring that sensitive data never exists in plaintext within the database.

The Key Provider Module

The open_notebook/ai/key_provider.py module serves as the bridge between stored credentials and the AI libraries. It exposes provision_provider_keys(), which normalizes provider names and routes to specialized provisioning functions like _provision_simple_provider, _provision_azure, and _provision_vertex. These functions query the database via Credential.get_by_provider(), decrypt the API key, and inject it into the current process environment using os.environ.

Provider Configuration Mapping

The architecture relies on a centralized PROVIDER_CONFIG mapping that associates provider names with their corresponding environment variable names. This prevents hardcoded strings throughout the codebase and ensures that when you integrate credential management with the key provider for API key lookup, the correct environment variables (such as OPENAI_API_KEY or AZURE_OPENAI_ENDPOINT) are populated consistently.

Implementation Flow

Creating and Storing Credentials

Before keys can be provisioned, they must be stored securely. The system exposes REST endpoints in api/routers/credentials.py for CRUD operations, or you can interact with the domain model directly. When creating a credential, the API key is wrapped in SecretStr and encrypted before persistence.

from open_notebook.domain.credential import Credential
from pydantic import SecretStr

async def create_openai_credential():
    cred = Credential(
        name="My OpenAI Key",
        provider="openai",
        modalities=["language", "embedding"],
        api_key=SecretStr("sk-REPLACE_WITH_REAL_KEY"),
        base_url=None,
    )
    await cred.save()

Provisioning Keys at Runtime

When an AI model is instantiated, the application calls await provision_provider_keys("provider_name") before initializing the Esperanto client. The function fetches the first matching credential from the database, decrypts the API key using cred.api_key.get_secret_value(), and sets the appropriate environment variable. If no database record exists, the system falls back to existing environment variables, maintaining backward compatibility with containerized deployments.

from open_notebook.ai.key_provider import provision_provider_keys

async def load_openai_key():
    success = await provision_provider_keys("openai")
    if success:
        print("OpenAI key loaded from Credential")
    else:
        print("Falling back to existing env var")

Complex Provider Configurations

Different AI providers require distinct environment variable schemas. For Azure OpenAI, _provision_azure extracts api_key, endpoint, and api_version to populate AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT, and related variables. For Google Vertex AI, _provision_vertex handles project, location, and GOOGLE_APPLICATION_CREDENTIALS file paths. Simple URL-based providers like Ollama utilize _provision_simple_provider to map the base_url field to <PROVIDER>_API_BASE.

Practical Code Examples

Using Provisioned Keys with Esperanto Models

After provisioning, the Esperanto factory automatically reads the environment variables to authenticate with the provider:

from open_notebook.ai.models import Model
from open_notebook.ai.key_provider import provision_provider_keys

async def create_gpt4_model():
    await provision_provider_keys("openai")
    model = Model.create_language(model_name="gpt-4")
    return model

Bulk Provisioning at Startup

While per-provider provisioning is preferred to avoid stale credentials, you can load all keys at once using provision_all_keys():

from open_notebook.ai.key_provider import provision_all_keys

async def initialize_all_providers():
    results = await provision_all_keys()
    print("Provisioned:", results)

Retrieving Specific API Keys

For direct access without setting environment variables, use get_api_key():

from open_notebook.ai.key_provider import get_api_key

async def fetch_key_directly():
    api_key = await get_api_key("openai")
    if api_key:
        print(f"Retrieved key: {api_key.get_secret_value()}")

Summary

  • Database-first storage: Credentials live encrypted in SurrealDB via the Credential model in open_notebook/domain/credential.py, enabling UI-driven management and audit trails.
  • Lazy environment injection: The key provider in open_notebook/ai/key_provider.py injects secrets into os.environ only when provision_provider_keys() is called, minimizing exposure windows.
  • Provider-specific routing: Functions like _provision_azure and _provision_vertex handle complex multi-variable configurations for enterprise AI providers.
  • Zero-downtime fallback: When no database credential exists, the system transparently falls back to existing environment variables, ensuring compatibility with existing deployment scripts.

Frequently Asked Questions

How does Open Notebook encrypt API keys before storing them?

The Credential model in open_notebook/domain/credential.py uses the _prepare_save_data method to encrypt the api_key field before persistence. The encryption key is sourced from the application configuration in open_notebook/config.py, ensuring that only encrypted values are written to SurrealDB. When retrieved, the model decrypts the value automatically, exposing it only as a SecretStr object that reveals the plaintext only when explicitly requested via get_secret_value().

What happens if a credential exists in the database and in an environment variable?

When provision_provider_keys() is called, it checks the database first via Credential.get_by_provider(). If a database record exists, its decrypted value overwrites the environment variable for the current process. If no record exists, the function preserves the existing environment variable value. This database-first approach ensures that user-managed credentials take precedence over system-level configuration while maintaining fallback compatibility.

Can I use the key provider with self-hosted or custom AI endpoints?

Yes. For providers like Ollama or other URL-based services, store the base URL in the base_url field of the Credential record. The _provision_simple_provider function maps this value to <PROVIDER>_API_BASE in the environment. This allows the Esperanto library to connect to custom endpoints without modifying the core application code, as implemented in open_notebook/ai/key_provider.py.

When should I use provision_all_keys() versus provision_provider_keys()?

Use provision_provider_keys("provider_name") when you need to integrate credential management with the key provider for API key lookup for a specific AI model, as it prevents stale environment variables from lingering after credentials are deleted. Reserve provision_all_keys() only for startup initialization scenarios where multiple providers are required simultaneously, as it may populate environment variables for providers that are never used, slightly increasing the memory footprint of sensitive data.

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 →