API知识站学习、对比与使用指南
认证失败API Key / Authorization Header

401 Unauthorized:API 调用未通过认证怎么解决

请求已经发到 API 服务,但服务端没有接受你的身份凭证。优先检查 API Key、请求头、环境变量和 Base URL 是否属于同一个平台。

排查结论

先用最小请求隔离问题:只保留 API Key、Base URL、模型名和一条 ping 消息。最小请求失败,先修配置;最小请求成功,再回到业务代码排查并发、上下文和部署环境。

1. 问题现象

  • HTTP 状态码返回 401,响应里出现 Unauthorized、invalid_api_key、Incorrect API key 或 authentication failed。
  • 同一段代码昨天能跑,今天突然全部失败,通常是 Key 被删除、过期、轮换或账号权限变化。
  • 控制台能正常登录,但 SDK、curl、Claude Code、Codex 或其他工具调用失败。
  • 返回的是 HTML 登录页或网关错误页,而不是 JSON 错误对象,说明请求可能打到了错误地址。

2. 最可能原因

Authorization 请求头缺失,或没有使用 Bearer 前缀。
环境变量没有加载成功,代码实际传入的是空字符串、undefined 或旧 Key。
复制 API Key 时带了空格、换行、引号,或只复制了部分内容。
把 A 平台的 Key 用在 B 平台的 Base URL 上,例如 OpenAI Key 配了 DeepSeek Base URL。
Key 被删除、禁用、泄露后被轮换,或创建在另一个项目/组织下。

3. 快速排查清单

1

确认代码实际读到 Key

只打印长度和前后 4 位,不要打印完整 Key;长度为 0 或前缀不对时先修环境变量。

2

确认请求头格式

OpenAI 兼容接口通常是 Authorization: Bearer <API_KEY>;不要写成 Token、Basic 或只传裸 Key。

3

确认 Key 和 Base URL 属于同一平台

DeepSeek Key 配 https://api.deepseek.com,Kimi Key 配 https://api.moonshot.cn/v1,通义千问 Key 配 DashScope 兼容模式地址。

4

重新生成一个最小权限测试 Key

如果新 Key 可用,旧 Key 就是被删、过期、权限错误或复制错误。

5

用 curl 跳过业务代码测试

先用最小请求确认认证能通过,再回到 SDK 或工具配置。

4. 对应 API 的特殊情况

OpenAI

ChatGPT Plus/Pro 订阅不等于 API 额度。API Key 还要确认所属 Project、组织和 Billing 状态。

Claude / Anthropic

直连 Anthropic Messages API 使用 x-api-key 和 anthropic-version;不要把 Anthropic Key 当成 OpenAI Bearer Key 直接打 OpenAI 路径。

DeepSeek / Kimi / 通义千问

这些平台常用 OpenAI 兼容 SDK,但 base_url 必须换成各自平台地址,Key 也必须来自同一个平台控制台。

豆包火山方舟

model 经常是控制台里的推理接入点 ID;Key 正确但模型 ID 填错时也可能伴随认证或权限类错误。

5. 可复制的修复示例

用 curl 验证 Bearer Token 是否有效
bash
export API_KEY="sk-替换成你的真实Key"
export BASE_URL="https://api.deepseek.com"

curl -i "$BASE_URL/v1/models" \
  -H "Authorization: Bearer $API_KEY"
如果这里仍是 401,问题在 Key、Base URL 或账号权限,不在业务代码。
Python 中安全检查环境变量是否加载
python
import os
from openai import OpenAI

api_key = (os.getenv("DEEPSEEK_API_KEY") or "").strip()
if not api_key:
    raise RuntimeError("DEEPSEEK_API_KEY 没有加载")

print("key_loaded", len(api_key), api_key[:4] + "..." + api_key[-4:])

client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")
print(client.models.list().data[0].id)
只打印脱敏信息,确认程序读到的是当前 Key。