401 Unauthorized在Composer中主因是Authorization头未发出,根源在于auth.json配置错误、域名不匹配或文件未生效;须用composer config命令写入、严格校验JSON格式与权限,并通过composer diagnose确认凭据是否真实加载。

401 Unauthorized 不是密码错了,而是 Composer 根本没把 Authorization: Basic 头发出去——原因几乎全是配置没对上、文件没生效或域名不匹配。
用 composer config http-basic 命令写入才真正生效
手动改 auth.json 容易出错:JSON 格式非法、字段名拼错、多逗号、单引号、注释……Composer 全部静默忽略。命令行方式会自动校验结构、base64 编码、权限设置,且只写入合法字段。
- 项目级(推荐):
composer config http-basic.packages.example.com deploy 'p@ss$w!rd'(密码含$、!等必须用单引号包裹) - 全局级:
composer config --global http-basic.repo.internal.org ci-bot '${CI_TOKEN}'(支持环境变量展开) - 执行后立刻验证:
composer config --list | grep http-basic(项目级)或composer config --global --list | grep http-basic(全局)
auth.json 的域名必须和仓库 URL 的 host 部分完全一致
Composer 匹配凭据时只看 HTTP 请求头里的 Host 字段,不解析协议、路径、端口(除非显式指定)。填错一个字符,认证就失效。
- 仓库 URL 是
https://packages.myorg.com/api/v2→ 域名必须配packages.myorg.com,不是myorg.com,也不是https://packages.myorg.com - 仓库 URL 是
https://gitlab.company.com→ 配gitlab.company.com,不是company.com或gitlab.company.com/ - 多个私有源要分别配:
packages.a.com和packages.b.net不能合并,也不能用通配符
auth.json 文件位置、权限、格式三者缺一不可
Composer 查找 auth.json 是“找到即停”,不会合并多个文件;权限或格式错,它连读都不读,更不会报错。
- 优先级顺序:
./auth.json(项目根目录) >$COMPOSER_HOME/auth.json(Linux/macOS 默认是~/.composer/auth.json或~/.config/composer/auth.json) - Linux/macOS 下权限必须 ≤600:
chmod 600 auth.json,否则静默跳过 - 正确 JSON 结构只允许一层:
{"http-basic":{"packages.example.com":{"username":"u","password":"p"}}},不能有注释、不能多逗号、不能用单引号、不能嵌套在repositories里
为什么 composer install 还是 401?先看 composer diagnose
这个命令会真实触发认证加载逻辑,并输出 “Checking http-basic authentication” 及其下面列出的已加载域名。这是唯一能确认“是否真读进来了”的方式。
- 如果没看到任何
http-basic行 →auth.json没被找到(位置错 / 权限错 / 名字拼错) - 如果列出了域名但和你仓库 URL 的 host 不一致 → 域名配错
- 如果列出了正确域名但仍是 401 → 检查
composer.json中repositories的type是否为"composer",且url带协议、不以/结尾(如"https://packages.example.com"✅,"packages.example.com/"❌)
最常被忽略的是:认证本身不解决 TLS 问题。如果私有源用自签名证书,401 可能是假象——实际是连接失败后返回了 HTML 登录页,导致 Composer 解析失败。这时得单独配 cafile 或临时关掉 secure-http,和 http-basic 是两件事。











