Protect API Keys
The Key Is the Account
An API key is a bearer credential: whoever holds it can make requests as the account that issued it, and the bill for those requests goes to that account. Nothing else is checked. There is no second factor, no device, and no location that must match. For that reason the key deserves the same care as a bank password, and an unprotected key is one of the most common ways that a model integration causes real damage, through unexpected charges, data exposure, or misuse of the account's privileges.
This lesson covers where keys should and should not appear, how to scope them so that a leaked key does less harm, how to recognize a key in text so that it can be removed, and what to do when a key has been exposed. The lessons that follow build on this one: .env files (Lesson 172), version control (Lesson 173), and usage limits (Lesson 179) all assume the key has been handled correctly from the start.
Where a Key Must Never Go
A key is a secret in the same sense that a password is, and it tends to leak through the places developers use most. The list below is the working checklist:
| Location | Why it leaks |
|---|---|
| Source code | Every copy of the repository, and every clone, carries the key |
| Version control history | Deleting the file later does not remove the key from earlier commits |
| Logs and error messages | Log aggregators are read by many people, and they are kept for a long time |
| Screenshots and shared documents | Pasted into chat, tickets, or slides, the key is visible to everyone who sees them |
| Client-side code | A key in a web page or a mobile app can be read by anyone who downloads the app |
| Request URLs and query strings | URLs are recorded by proxies, browsers, and servers |
The client-side row deserves emphasis. An application that calls the model from a browser or a phone must send its requests through a server that holds the key, never directly from the device. The key is a server-side secret.
Scoping Keys to Limit the Damage
A single key that works everywhere is a single point of failure. Scoping divides the risk: each environment, each service, and each team uses its own key, so that a leak affects one part of the system, and revoking the key does not disrupt the rest. Keys can be organized by workspace, and a workspace can be given its own spending limits (Lesson 179). The rule is simple: a key should have the narrowest scope that still lets its service work.
Scoping also makes investigation possible. When a key appears in an unexpected place, its scope shows which service it belonged to, and which set of logs to search (Lesson 180).
Recognizing a Key in Text
A key that appears in logs, documentation, or a chat transcript should be found and removed. Keys have a recognizable prefix, which makes them detectable by pattern. The function below finds keys in text and replaces them with a placeholder, so the text can be stored or shared safely. The pattern is a sanity check on the prefix and the characters that follow it, and it should be combined with a scanner in the version control system (Lesson 173):
"""redact_keys.py: find API keys in text and replace them before the text is stored or shared."""
import re
KEY_PATTERN = re.compile(r"sk-ant-[A-Za-z0-9_-]{10,}")
def redact(text: str) -> str:
return KEY_PATTERN.sub("[REDACTED KEY]", text)
if __name__ == "__main__":
line = "Calling the API with key sk-ant-api03-EXAMPLEkeyvalue123 for the batch job."
print(redact(line))
print("contains a key after redaction:", bool(KEY_PATTERN.search(redact(line))))
Output:
Calling the API with key [REDACTED KEY] for the batch job.
contains a key after redaction: False
How It Works
- The pattern matches the key prefix and what follows it. The characters after the prefix must be at least ten letters, digits, underscores, or hyphens, which covers the body of a key without matching ordinary words.
- Replacement is complete for every match.
subreplaces each occurrence, so a line that mentions two keys loses both. - The check at the end confirms the result. After redaction, the pattern no longer matches, which is the property that makes the text safe to store.
- The example key is fabricated. It has the shape of a key, and no real credential appears anywhere in this lesson.
The pattern cannot find every secret. It finds values that look like this platform's keys, and a key stored in a different format, or a password, needs its own pattern or a scanner. Redaction is a last line of defense, and the first line is never letting the key reach the text at all.
When a Key Has Been Exposed
A key that has been seen by someone it should not have reached must be treated as compromised, even if there is no evidence of misuse. The response has a fixed order. First, revoke the key, so that it stops working. Second, create a replacement and deploy it to the services that use it. Third, review the usage logs for the period when the key was exposed, to see whether it was used by someone else (Lesson 180). Fourth, find and remove every copy of the key, including in version control history, and rotate any other secret that was stored alongside it.
The order matters. Revoking first stops the damage, and replacing second restores service. Investigating before revoking lets the exposure continue while the investigation runs.
Summary
An API key is a bearer credential that authorizes spending and access, and it must never appear in source code, logs, screenshots, client-side code, or URLs. Scoping keys by environment and service confines the damage from a leak, and pattern-based redaction removes keys from text that must be stored or shared. An exposed key is revoked first, replaced second, investigated third, and purged everywhere it was copied. The next lesson shows how a .env file keeps local keys out of the code while still making them available to the application.