# Configuring API Keys and Environment Variables in Summarize: A Complete Security Guide

> Secure your Summarize setup by mastering API key and environment variable configuration. Learn best practices and understand precedence for robust security in your steipete/summarize project.

- Repository: [Peter Steinberger/summarize](https://github.com/steipete/summarize)
- Tags: best-practices
- Published: 2026-02-19

---

**Summarize reads API credentials from environment variables with optional config file overrides, resolving values in a strict precedence chain where process-level environment variables take highest priority.**

The `steipete/summarize` repository implements a robust, layered approach to configuring API keys and environment variables that balances security with flexibility. Understanding how the system resolves credentials across environment variables, JSON/YAML configuration files, and CLI overrides ensures you can deploy safely without exposing secrets in version control.

## How Summarize Resolves API Credentials

The credential resolution system is implemented across several core files that work together to build a secure `EnvState` object used by the summary engine.

### The Configuration Resolution Pipeline

In [`src/config.ts`](https://github.com/steipete/summarize/blob/main/src/config.ts) (lines 43-55), the system maps legacy `apiKeys` shortcuts from your configuration file to standard environment variable names. For example, an `openai` key under `apiKeys` gets mapped to `OPENAI_API_KEY` internally.

The central resolver in [`src/run/run-env.ts`](https://github.com/steipete/summarize/blob/main/src/run/run-env.ts) (lines 37-85) merges multiple sources into a final `EnvState`:

1. **Process-level environment variables** (`process.env`) — highest priority
2. **Config-file API-key shortcuts** (`apiKeys` section)
3. **General `env` block in the config file** — lowest priority

This resolver also normalizes keys by trimming whitespace and supporting legacy naming variations like `ZAI_API_KEY` and `Z_AI_API_KEY`.

### Runtime Validation

Before making any API calls, [`src/run/summary-engine.ts`](https://github.com/steipete/summarize/blob/main/src/run/summary-engine.ts) (lines 9-41) validates that required environment variables are present through the `envHasKeyFor()` function. Each model declares its `requiredEnv` metadata in [`src/model-spec.ts`](https://github.com/steipete/summarize/blob/main/src/model-spec.ts) (lines 19-27), specifying which environment variable must be satisfied before execution.

## Required Environment Variables by Model Provider

Different AI providers require specific environment variables. The engine checks for these via the `requiredEnv` field in the model specification:

- **OpenAI-compatible models**: `OPENAI_API_KEY` (or OpenRouter fallback)
- **Google Gemini**: `GEMINI_API_KEY` (alternatively `GOOGLE_GENERATIVE_AI_API_KEY` or `GOOGLE_API_KEY`)
- **Anthropic**: `ANTHROPIC_API_KEY`
- **xAI**: `XAI_API_KEY`
- **ZAI**: `Z_AI_API_KEY` (with legacy support for `ZAI_API_KEY`)
- **NVIDIA**: `NVIDIA_API_KEY`
- **OpenRouter**: `OPENROUTER_API_KEY` (can be derived from an OpenAI key when using an OpenRouter base URL)
- **CLI providers**: No environment variable required; instead the binary must be discoverable via `resolveCliAvailability`

If a required key is missing, the engine throws a descriptive error:

```text
Missing OPENAI_API_KEY for model openai/gpt-4o-mini. Set the env var or choose a different --model.

```

## Configuration Methods and Examples

Summarize supports multiple configuration strategies to accommodate different deployment scenarios.

### Using .env Files for Local Development

For local development, create a `.env` file in your project root (ensure this is added to `.gitignore`):

```text

# .env  (do NOT commit this file)

OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GEMINI_API_KEY=AIzaSy....
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxx

```

The CLI automatically loads these using `dotenv` when present.

### Inline Environment Overrides

For temporary overrides without modifying files:

```bash
OPENAI_API_KEY=sk-abc123 summarize --model openai/gpt-4o-mini https://example.com/article

```

This takes advantage of the process-level environment variable precedence.

### The apiKeys Configuration Block

The `summarize.jsonc` or [`summarize.yaml`](https://github.com/steipete/summarize/blob/main/summarize.yaml) file supports an `apiKeys` section for portable defaults:

```json5
{
  // summarize.jsonc
  "apiKeys": {
    "openai": "sk-abc123",      // will be mapped to OPENAI_API_KEY
    "google": "AIzaSy-xyz"      // will be mapped to GEMINI_API_KEY
  },
  "model": "auto",
  "env": {
    "SUMMARIZE_YT_DLP_PATH": "/usr/local/bin/yt-dlp"
  }
}

```

Values set here are overridden by actual environment variables.

### OpenRouter Integration via Base URL

When using OpenRouter, you can leverage automatic key inference:

```bash
export OPENAI_BASE_URL=https://openrouter.ai/api/v1
export OPENAI_API_KEY=sk-oa-xyz   # OpenAI key, will be used as OpenRouter key

summarize --model openrouter/openai/gpt-4o-mini https://example.com

```

The resolver in [`src/run/run-env.ts`](https://github.com/steipete/summarize/blob/main/src/run/run-env.ts) detects the OpenRouter base URL and populates `envForAuto` with the derived `OPENROUTER_API_KEY`, enabling auto-selection logic to recognize availability without manual key duplication.

## Security Best Practices

Follow these guidelines to maintain secure credential management when configuring API keys and environment variables:

1. **Keep secrets out of source control** — Add `.env` files to `.gitignore` and never commit raw API keys.
2. **Prefer environment variables for per-run overrides** — Use inline assignment for temporary keys to avoid persisting sensitive data.
3. **Use the `apiKeys` block only for one-off defaults** — This makes the config portable while still allowing env var overrides.
4. **Explicitly set the base URL when using OpenRouter** — Configure `OPENAI_BASE_URL` to enable automatic key derivation.
5. **Validate configuration before heavy work** — Run `summarize config validate` or test with `--model <id>` to catch missing keys early.
6. **Use the `env` block for non-secret defaults** — Store paths like `SUMMARIZE_YT_DLP_PATH` in config rather than environment variables.

The repository never logs raw API key values—only presence checks are performed in [`summary-engine.ts`](https://github.com/steipete/summarize/blob/main/summary-engine.ts), and telemetry masks sensitive data before transmission over TLS.

## Summary

- Summarize resolves API credentials through a strict precedence chain: process environment variables override config file `apiKeys`, which override the general `env` block.
- The central resolver in [`src/run/run-env.ts`](https://github.com/steipete/summarize/blob/main/src/run/run-env.ts) normalizes keys and handles legacy naming while building the `EnvState` object consumed by the engine.
- Each model declares `requiredEnv` metadata in [`src/model-spec.ts`](https://github.com/steipete/summarize/blob/main/src/model-spec.ts), validated at runtime by `envHasKeyFor()` in [`src/run/summary-engine.ts`](https://github.com/steipete/summarize/blob/main/src/run/summary-engine.ts).
- Store secrets in `.env` files excluded from Git, use inline environment variables for temporary overrides, and reserve the `apiKeys` config block for portable defaults.
- OpenRouter integration supports automatic key inference when `OPENAI_BASE_URL` points to the OpenRouter endpoint.

## Frequently Asked Questions

### What is the correct order of precedence for API keys in Summarize?

Summarize resolves credentials in three distinct layers: first, process-level environment variables take highest priority; second, values from the `apiKeys` block in your configuration file are applied; third, the general `env` block in the config provides fallback defaults. This chain is implemented in [`src/run/run-env.ts`](https://github.com/steipete/summarize/blob/main/src/run/run-env.ts) (lines 37-85), ensuring that sensitive credentials can always override portable configuration defaults.

### Can I use a single configuration file across different machines without exposing my API keys?

Yes, by using the `apiKeys` section sparingly and relying primarily on environment variables. Place your actual secrets in machine-local `.env` files that are excluded from version control, while keeping the `summarize.jsonc` or [`summarize.yaml`](https://github.com/steipete/summarize/blob/main/summarize.yaml) file in your repository with non-sensitive defaults. The `apiKeys` block is designed for convenience but is overridden by environment variables, making it safe to include placeholder or development keys that production environments can supersede.

### How does Summarize handle OpenRouter authentication without an explicit OPENROUTER_API_KEY?

When you set `OPENAI_BASE_URL` to `https://openrouter.ai/api/v1`, the resolver in [`src/run/run-env.ts`](https://github.com/steipete/summarize/blob/main/src/run/run-env.ts) detects this OpenRouter endpoint and automatically populates `OPENROUTER_API_KEY` using your existing `OPENAI_API_KEY` value. This inference happens during the `resolveEnvState` execution, enabling the auto-selection logic to recognize OpenRouter availability without requiring you to manually duplicate keys across different environment variable names.

### What happens if a required API key is missing at runtime?

Before making any API calls, the `envHasKeyFor()` function in [`src/run/summary-engine.ts`](https://github.com/steipete/summarize/blob/main/src/run/summary-engine.ts) (lines 9-41) validates that the environment contains the specific variable declared in the model's `requiredEnv` metadata from [`src/model-spec.ts`](https://github.com/steipete/summarize/blob/main/src/model-spec.ts). If the check fails, the engine throws a descriptive error message such as `Missing OPENAI_API_KEY for model openai/gpt-4o-mini. Set the env var or choose a different --model.`, halting execution before any network request is attempted.