When you build an application with LangChain, the first step is often not writing a chain but getting the key right. The same code may work locally and return 401 after deployment, or someone pastes a key into a notebook and forgets to clean it up. Most of these problems are not about the framework; they are about where the key comes from, the order in which configuration loads, and where permission boundaries sit.
This article follows the order "source, configuration, isolation, rotation, troubleshooting" to explain how API keys should be managed in a LangChain project. For specific models, quotas, and prices, refer to the model pricing page and the documentation of the provider you use.
Note: LangChain is a trademark of LangChain, Inc. This article is a technical configuration guide and is not affiliated with, or partnered with, LangChain, Inc. Integration package behavior may change between versions; follow the documentation for the version you use.
1. First distinction: LangChain does not issue model keys
LangChain is an open-source application development framework that orchestrates models, tools, retrieval, and workflows. It generally does not include model usage quota, so there is no such thing as a "LangChain model key." The credential you put into LangChain actually belongs to a model provider, a cloud platform, or an AI gateway.
Projects commonly involve at least three types of credentials, with completely different purposes:
| Credential | Purpose | Where to obtain it |
|---|---|---|
| Model API key | Call chat, reasoning, embedding, and other models | Model provider or AI gateway console |
LANGCHAIN_API_KEY |
LangSmith tracing and evaluation | LangSmith, only needed when observability is enabled |
| Cloud platform credentials | Access hosted models or cloud resources | The corresponding cloud vendor's access console |
Combining all three into one key makes permissions too broad and rotation difficult. Separate them by purpose first, then configure.
2. Environment variables: defaults and explicit passing
ChatOpenAI from langchain-openai reads OPENAI_API_KEY by default; for OpenAI-compatible endpoints, specify the address with the base_url parameter. A minimal working setup looks like this:
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
# Read from a .env file near the project; in production prefer system environment variables or a secrets manager
load_dotenv()
llm = ChatOpenAI(
model=os.environ["ZSQH_MODEL"], # Model ID: see the pricing page
api_key=os.environ["ZSQH_API_KEY"], # The default OPENAI_API_KEY also works
base_url="https://ai.zhongshangqihang.com/v1",
temperature=0,
)
print(llm.invoke("Explain in one sentence what an API gateway is").content)
A few details that are easy to overlook:
- Environment variables are read when the client object is created, not when the module is imported. In a notebook, after assigning
os.environmid-session, create a newChatOpenAIinstance. - Passing an empty string explicitly overrides the environment variable. When debugging a 401, first look for leftovers such as
api_key=""in the code. - Different integration packages read different variable names. Anthropic and Google each have their own conventions; follow the matching documentation.
init_chat_modelcan create models from different providers through one interface, but additional parameters and default variables still depend on the underlying integration. Re-test after upgrades.
3. .env and SecretStr: two lines of defense for local development
A .env file is convenient for local development, but it must come with two rules.
First, .env never enters version control. Add it to .gitignore when the project is initialized, and commit a .env.example without real values so new team members know which variables are required. If a key was committed by mistake, deleting the file does not erase repository history. Revoke the key immediately, then deal with the history.
Second, understand LangChain's SecretStr. The key field of ChatOpenAI is usually stored as a SecretStr, so printing the object or writing logs shows a masked value rather than plaintext. That blocks some accidental output, but it does not stop an explicit get_secret_value(), manual header construction, or printing the entire request in an exception. Do not treat framework masking as permission to log freely.
For container deployments, do not bake keys into images: build arguments and image layers may both be retained. Inject them at runtime through environment variables or a secrets manager.
4. Multiple providers, multiple models: one key or several?
The answer depends on whether the entry point is unified. With an AI gateway, one gateway key can usually call multiple models, with the model selected by the model parameter. When connecting directly to several vendors, you often need a separate key for each.
Use readable variable names and standardize them across the team:
- Gateway style:
ZSQH_API_KEY,ZSQH_BASE_URL. - Vendor style: follow integration package conventions, such as
ANTHROPIC_API_KEYandGOOGLE_API_KEY. - Environment suffix:
_DEV,_STAGING,_PROD, so test keys do not reach production.
Multiple models also means fallback and routing. LangChain can switch to a backup model with .with_fallbacks() when the primary model fails, but each backup model still needs its own authentication configuration. Do not assume that "one key can call every model": a gateway may enforce a model allowlist, and vendor keys may only be enabled for some models. Available model IDs are listed on the model pricing page.
5. Least privilege: split keys by environment and purpose
The goal of key management is not "as few keys as possible" but "boundaries as clear as possible." Practical steps:
- Use separate keys for development, staging, and production. Production keys should not sit on developer laptops.
- Give every application and every team member a separate key; sharing one key among people is not acceptable.
- Set lower budgets for test keys and limit which models they can call.
- When the console supports IP allowlists, quota alerts, or model allowlists, turn all of them on.
- Keep only the last few characters of a key in logs, tickets, and screenshots.
If the gateway supports usage reporting per key, that key can serve both cost accounting and incident diagnosis. A shared "universal key" makes abnormal bills impossible to attribute.
6. Rotation and revocation: create new, shift traffic, then revoke
Rotate at least every 90 days, and immediately after staff departures, device loss, misconfigured deployments, or suspected leaks. The order matters:
- Create a new key in the console, with a date or version in the name, for example
prod-app-202610. - Write the new key into the secrets manager or the deployment platform's environment variables.
- Restart or redeploy the application and confirm the new process has loaded the new value.
- Send a real request to confirm the model responds and usage is recorded against the new key.
- Watch for a period to confirm no forgotten old instances are still calling.
- Only then revoke the old key and update the internal inventory.
When keys are read from environment variables, rotation usually requires no code change, but it does require a restart or rolling deployment. Long-lived connections or resident processes may keep using the old key, so confirm all instances have been replaced before revoking.
7. CI and team collaboration: keep keys out of logs
CI environments combine automated execution with log retention, which makes them a common source of key leaks. A few baseline rules:
- Store keys in the CI platform's encrypted secrets, not in plaintext in pipeline files.
- Disable debug options that echo commands, so
set -xdoes not print request headers. - Create a dedicated key for CI with a low budget and a restricted model list.
- Use a secret-scanning tool as a pre-commit check and block suspected keys immediately.
- During code review, inspect
.envfiles, configuration files, and test snapshots as sensitive files.
Team handover documentation should state: who owns each key, its purpose, creation date, next rotation date, and the revocation procedure for departures and device loss.
8. Troubleshooting: confirm the variable, then the protocol
When authentication fails, check in this order; it is usually faster than recreating keys repeatedly:
- Confirm the variable reached the process: print only whether it exists, never its value. Restart the kernel in a notebook, and in containers confirm injection reached the right service.
- Check explicit overrides: look for an empty
api_keyor an incorrectbase_urlin code or configuration. - Check the protocol path: OpenAI-compatible endpoints usually end at
/v1; a missing or extra segment typically produces a 404. - Check the model ID: a display name is not an API identifier; compare character by character with the pricing page.
- Route by status code: 401 points to the key itself, 403 to permissions and model scope, 429 to concurrency and quota, and 5xx to retry with the request timestamp retained.
- Check network and proxy: proxy environment variables and corporate gateway certificates can cause failures that look like authentication problems.
Change one variable at a time. Swap the key first, then the model, so you can quickly tell whether "this key does not work" or "this model is unavailable" is the real issue.
FAQ
Does LangChain itself need an API key?
The framework itself does not. Credentials are only needed when calling remote models, embedding services, or LangSmith observability services.
I set the environment variable, so why do I still get a 401?
Four common causes: the variable only applies to the current terminal, the notebook kernel was not restarted, the code passes an empty key explicitly, and the key has leading or trailing spaces or line breaks. Confirm the variable exists inside the process, then check whether code overrides it.
Can one key call multiple models at once?
It depends on the service the key belongs to. A unified gateway usually allows one key to call multiple models on its list; when connecting directly to vendors, each vendor has its own key. Even when multiple models are supported, an allowlist may apply, so the console permissions are authoritative.
Will keys appear in LangSmith traces?
Traces mainly store inputs, outputs, and the call chain; whether request headers are included depends on the integration and redaction settings. Do not treat a tracing platform as a key vault. Custom callbacks, exception logs, and debugging proxies are more likely to leak request headers, so review redaction settings before enabling them.
Does rotating a key require code changes?
If the code reads from environment variables or a secrets manager, usually no code change is needed; update the value and restart or redeploy. If the key is hardcoded in code, a notebook, or an image, move it to external injection first, then rotate.
Next steps
Key management in LangChain comes down to four sentences: keys belong to model providers, not the framework; use .env locally and a secrets manager in production; split keys by environment and purpose; create the new key before revoking the old one. If you need a unified multi-model entry point with per-key usage and quota management, you can sign up for ZSQH AI Gateway; models and prices are listed on the model pricing page.
Related reading:
