API Key Management in Python — Core Concepts
Two sides of API keys
API key management has two perspectives:
Consuming keys — your app uses someone else’s API key (Stripe, OpenAI, Twilio). Your job is to store these keys securely and never leak them.
Issuing keys — your app provides API keys to your customers. Your job is to generate them securely, validate them efficiently, and support rotation.
Consuming API keys safely
The golden rule: never put API keys in source code. Code ends up in version control, gets shared, and leaks. Instead:
Environment variables — the simplest approach:
import os
api_key = os.environ["OPENAI_API_KEY"]
# Fails loudly if the variable isn't set
.env files with python-dotenv — for local development:
from dotenv import load_dotenv
import os
load_dotenv() # reads .env file
api_key = os.environ["STRIPE_SECRET_KEY"]
Always add .env to .gitignore. Never commit it.
Secret managers — for production: AWS Secrets Manager, HashiCorp Vault, Google Secret Manager, or Azure Key Vault. These provide audit logging, rotation, and access control that environment variables can’t.
Generating API keys
When your application issues keys to customers, they need to be:
- Unpredictable — cryptographically random, not sequential
- Unique — no two keys should ever collide
- Identifiable — you should be able to tell which customer owns a key without a database lookup (using a prefix)
- Revocable — you can disable individual keys without affecting others
import secrets
def generate_api_key(prefix: str = "sk") -> str:
"""Generate a prefixed API key."""
random_part = secrets.token_urlsafe(32)
return f"{prefix}_{random_part}"
# sk_dGhpcyBpcyBhIHNhbXBsZSBrZXk...
Prefixes like sk_live_, sk_test_, pk_ (Stripe’s convention) help developers and automated tools identify key types and prevent mixing test and production keys.
Storing issued keys
Store API keys like passwords — hashed, not in plaintext. If your database leaks, plaintext keys are immediately exploitable.
Hash the full key and store the hash. When a request comes in, hash the provided key and look up the hash. Keep only the first few characters in plaintext (like sk_live_abc...) so customers can identify their keys in a dashboard.
Validating API keys
For every incoming request:
- Extract the key from the
Authorizationheader (orX-API-Keyheader) - Hash it
- Look up the hash in your database
- Check if the key is active, not expired, and not rate-limited
- Load the associated permissions
Key rotation
Keys need to change periodically or after suspected compromise. Good key management lets customers:
- Generate a new key while the old one still works (overlap period)
- Test the new key in their systems
- Deactivate the old key once migration is complete
Supporting multiple active keys per customer makes rotation seamless.
Common misconception
“API keys are a secure authentication method.” API keys identify the caller, but they’re not a substitute for proper authentication. They travel in every request (often as URL parameters or headers), can be logged by intermediate proxies, and don’t support scoping by IP or time. For user-facing APIs, prefer OAuth 2.0. API keys are best for server-to-server communication where the key stays on the server.
The one thing to remember: API key management means generating unpredictable keys with identifiable prefixes, storing them hashed in the database, and supporting rotation so keys can be replaced without downtime.
See Also
- Python Attribute Based Access Control How apps make fine-grained permission decisions based on who you are, what you're accessing, and the circumstances — explained with an airport analogy
- Python Audit Logging Learn Audit Logging with a clear mental model so your Python code is easier to trust and maintain.
- Python Bandit Security Scanning Why Bandit Security Scanning helps Python teams catch painful mistakes early without slowing daily development.
- Python Clickjacking Prevention How invisible website layers trick you into clicking the wrong thing, and how Python apps stop it
- Python Content Security Policy How websites create a guest list for scripts and styles to block hackers from sneaking in malicious code