# Secure API Key Management with Environment Variables in ai-hedge-fund

> Learn secure API key management in ai-hedge-fund by loading credentials from environment variables. Access tokens only at runtime for enhanced security.

- Repository: [Virat Singh/ai-hedge-fund](https://github.com/virattt/ai-hedge-fund)
- Tags: best-practices
- Published: 2026-03-09

---

**The virattt/ai-hedge-fund repository eliminates hard-coded secrets by loading API credentials from environment variables into a centralized state object, then retrieving them through the `get_api_key_from_state` helper to ensure tokens are only accessible at runtime.**

The virattt/ai-hedge-fund project handles sensitive credentials for OpenAI, Alpha Vantage, and Ollama services through a rigorous environment-variable architecture. This secure API key management strategy keeps authentication tokens out of version control while providing trading agents with seamless access to external data sources. By routing all credential access through a single utility in [`src/utils/api_key.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py), the codebase maintains strict separation between secret configuration and business logic.

## Architecture Overview: From Environment to Execution

The repository implements a three-layer defense that prevents accidental credential exposure. At the outer layer, environment variables supply raw secrets via a template file. These values flow into a global state object during application bootstrap in [`src/main.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/main.py), then get retrieved on-demand by services through a type-safe helper function.

### Layer 1: Environment Configuration (.env.example)

The repository provides [.env.example](https://github.com/virattt/ai-hedge-fund/blob/main/.env.example) as a template that documents required secrets without exposing real values. Developers copy this file to `.env` and populate it with actual keys, or inject the variables directly through Docker, Kubernetes, or CI/CD secret managers.

```bash

# .env.example – Environment variable templates

# OpenAI LLM integration

OPENAI_API_KEY=your-openai-key-here

# Alpha Vantage market data

ALPHAVANTAGE_API_KEY=your-alpha-vantage-key

# Ollama self-hosted endpoint

OLLAMA_BASE_URL=http://localhost:11434

```

### Layer 2: Runtime State Population

During application startup, [`src/main.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/main.py) reads the environment variables and injects them into the workflow state. This state object acts as a secure container that travels through the agent execution pipeline, ensuring API keys remain available but isolated from direct global scope access.

### Layer 3: Secure Retrieval via api_key.py

The [src/utils/api_key.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py) file provides the `get_api_key_from_state` function, the sole authorized pathway for accessing credentials. This helper navigates the nested state structure—checking `state["metadata"]["request"].api_keys`—to extract specific keys only when requested by legitimate services.

```python

# src/utils/api_key.py – Centralized credential retrieval

def get_api_key_from_state(state: dict, api_key_name: str) -> str:
    """Get an API key from the state object."""
    if state and state.get("metadata", {}).get("request"):
        request = state["metadata"]["request"]
        if hasattr(request, "api_keys") and request.api_keys:
            return request.api_keys.get(api_key_name)
    return None

```

## Practical Implementation in LLM Services

When constructing requests to external LLMs, the codebase uses the helper to inject authentication headers without exposing the raw key in service logic. The [src/utils/llm.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/llm.py) file demonstrates this pattern, explicitly noting where extraction occurs.

```python

# src/utils/llm.py – Secure key extraction for LLM requests

def build_llm_payload(state: dict, model: str, prompt: str):
    # Extract API keys from state if available

    api_key = get_api_key_from_state(state, "openai")
    headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
    
    return {
        "model": model,
        "prompt": prompt,
        "headers": headers,
    }

```

## Key Files and Their Security Roles

- **[.env.example](https://github.com/virattt/ai-hedge-fund/blob/main/.env.example)** – Template documenting required environment variables without exposing real secrets.
- **[src/utils/api_key.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py)** – Centralized helper that extracts API keys from the execution state, preventing scattered credential access.
- **[src/utils/llm.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/llm.py)** – Demonstrates secure key retrieval when building external API requests.
- **[src/main.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/main.py)** – Application entry point that loads environment variables into the global state object.
- **[src/tools/api.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/tools/api.py)** – Service layer wrapper that expects keys via the state-based helper for HTTP authentication.

## Summary

- **Environment isolation**: All API credentials live in environment variables defined by `.env.example` templates, never in source code.
- **State-based routing**: The `get_api_key_from_state` function in [`src/utils/api_key.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py) provides the exclusive pathway for credential retrieval, centralizing access control.
- **Service-layer abstraction**: LLM and data services pull keys from the runtime state on demand, enabling secure header injection without hard-coded strings.
- **CI/CD compatibility**: The architecture supports secret injection through standard environment variable mechanisms used by Docker, GitHub Actions, and cloud platforms.

## Frequently Asked Questions

### How does ai-hedge-fund prevent API keys from being committed to Git?

The repository only commits the [.env.example](https://github.com/virattt/ai-hedge-fund/blob/main/.env.example) file containing placeholder values like `your-openai-key-here`. Actual credentials are loaded from a local `.env` file or CI/CD secrets manager at runtime, following the twelve-factor app methodology.

### What happens if an API key is missing at runtime?

The `get_api_key_from_state` function returns `None` when a requested key is absent from the state object. Downstream services check for this value and either raise explicit configuration errors or skip authentication headers, prompting operators to set the missing environment variable.

### Where is the get_api_key_from_state function defined?

The secure retrieval helper is implemented in [src/utils/api_key.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py). It extracts values from `state["metadata"]["request"].api_keys`, providing a single point of control for all credential access across the codebase.

### Can this pattern support external secrets managers?

Yes. Because the system reads from environment variables during bootstrap in [`src/main.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/main.py), you can populate those variables from AWS Secrets Manager, HashiCorp Vault, or Kubernetes secrets without modifying the retrieval logic in [`src/utils/api_key.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py).