September 12, 2026
API KEYS AND ENVIRONMENT VARIABLES

Lesson 14.1 drew the line between identity and permission. This lesson puts the most common machine identity in your hands: the API key. You already met environment variables in Class 4 as configuration. Now you learn why a key is configuration with consequences.
An API key looks boring — a long string of letters and digits. Treat it like a password taped to a credit card, because functionally that is what it is.
Four terms, precisely
- API key: a long secret string a service issues to identify (and bill) your project. You send it with each request, usually in an
Authorizationheader. - Bearer token: a credential where possession alone grants access — "whoever bears this token may enter." Most API keys work this way. Anyone holding the string gets the power; there is no second check.
- Secret: any value that must stay private to preserve security — API keys, tokens, passwords, signing keys. "Secret" describes how you must handle it, not its format.
- Environment variable: a named value stored outside your code that your program reads at runtime, like
OPENROUTER_API_KEY. The code names the variable; the environment supplies the value.
The pattern matters: code contains the *name*, the environment contains the *value*, and the two meet only when the program runs.
Why a key is not "just config"
A display theme never cost anyone money. A key can do three things ordinary settings cannot:
1. Spend money under your account — model calls, emails sent, compute burned. 2. Read private data — files, inboxes, customer records, private repositories. 3. Act as you — publish, delete, deploy, or change billing, up to the scopes attached to the key.
That is why an authenticated CLI is powerful. When you log into gh, vercel, supabase, or a model provider from your terminal, your coding agent inherits real authority through those stored credentials. The same terminal that inspects a deployment can promote one. Handle CLI credentials with the same discipline as keys: they are keys with a nicer interface.
The correct project pattern
Every project that touches a service should follow this shape:
.env → local secret, ignored by Git
.env.example → names only, safe to share
hosted environment → secret saved in deployment settings
application code → reads the variable; never contains the value
Concretely: your .env file holds OPENROUTER_API_KEY=sk-or-v1-abc123… and is listed in .gitignore so Git never tracks it. Your .env.example holds OPENROUTER_API_KEY= — the name, no value — so teammates and agents know what to provide. In production, the value lives in the host's environment settings (Vercel, Cloudflare, Supabase dashboards), never in the repository. Your code calls something like process.env.OPENROUTER_API_KEY and holds no secret itself.
Local machine Deployment host NEVER here
───────────── ─────────────── ──────────
.env (real value) → env settings (real value) ✗ Git repo
↓ ↓ ✗ Browser code
server code reads server code reads ✗ Screenshot
process.env.X process.env.X ✗ Chat message
Browser code deserves emphasis: anything shipped to a visitor's browser is public. A key embedded in frontend JavaScript is not stored — it is published. Keys belong in server-side code, CLIs, and deployment settings only.
Five ways keys escape
| Failure | How it happens | Why it hurts |
|---|---|---|
| Committed to Git | Key pasted into code or .env without ignoring it | History preserves it forever; scanners and strangers can find it |
| Pasted in a screenshot | Terminal or .env visible in a shared image or video | Credentials survive cropping less often than people hope |
| Shipped in frontend code | Key bundled into browser JavaScript | Every visitor receives your key with the page |
| Shared in chat | Key pasted into Slack, Discord, or an AI chat | Logs, exports, and other participants keep a copy |
| Left active after the project | Old key never revoked when the demo ended | A forgotten credential is an unattended open door |
When exposure happens: rotate, don't hide
If a key escapes — committed, screenshotted, pasted, shared — assume it is compromised and act in order:
1. Revoke or rotate the key in the provider dashboard immediately. Generate a replacement. 2. Replace it everywhere it is used — local .env, deployment settings, teammate copies. 3. Check deployment and Git history. Remove the value from current files, and know that history may still hold it — ask for help rewriting history if the repository is shared. 4. Inspect for misuse — unexpected usage, charges, or unfamiliar activity in the provider dashboard.
Do not merely delete the visible copy and hope. Revocation is the fix; cleanup is hygiene afterward.
Practical exercise: write the names, not the values
Finish line: a fictional .env.example plus a .gitignore entry, with zero real secrets in either file.
1. Create .env.example for a fictional app:
OPENROUTER_API_KEY=
SUPABASE_URL=
SUPABASE_ANON_KEY=
2. Confirm your .gitignore contains .env (and ideally .env*.local). Verify with git status that no .env file is tracked. 3. Write one sentence per variable saying what power it grants — "bills model usage," "reads project database."
Verify: run a search for sk- across your project and confirm no real key appears in tracked files. Common failure mode: .env was committed before .gitignore was added — Git keeps tracking it until you untrack it, so ignoring alone does not clean history.
Check your understanding
1. What is a bearer token, and why does that property make leaks dangerous? 2. What belongs in .env, what belongs in .env.example, and what belongs in neither? 3. Why must API keys never appear in frontend browser code? 4. Name three ways keys escape and the correct first response when one does. 5. Why does an authenticated CLI deserve the same caution as a raw API key?
Toward consent
Keys prove a machine's identity simply — whoever holds the string gets in. But what happens when the data belongs to someone else, and they should grant your app only a slice of access without handing over their password? That is the problem OAuth solves, and it is Lesson 14.3.
ARTICLE DISCUSSION
JOIN THE
CONVERSATION.
Got a question, a take, or a better way to do this? Log in and leave a comment.
