composer 不检测 token 过期,仅在请求时抛出 could not authenticate 错误;需在 ci 中前置校验 github/gitlab api,依赖 composer_auth 或全局 auth.json,注意 fine-grained token 与 composer 版本兼容性。

Composer auth.json 令牌过期不会自动告警
Composer 本身不检测 Personal Access Token 是否过期,也不在 install/update 前主动验证 GitHub/GitLab 凭据有效性。所谓“授权过期”实际表现为 Could not authenticate 错误——它只在真正发起 HTTP 请求时才暴露,不是提前预警,而是运行时失败。
常见现象包括:Could not authenticate against github.com、Failed to download vendor/package: Invalid credentials for https://github.com/。这不是配置漏了,而是 Token 已被平台吊销、过期或权限被回收(比如 GitHub 启用 fine-grained token 后 classic token 自动失效)。
- GitHub classic token 默认有效期为永久,但用户可手动 revoke;fine-grained token 必须显式设 expiry,且默认 30 天
- GitLab 的 Personal Access Token 也支持 expiry,但 Composer 不读取其剩余有效期字段
- 私有 Packagist 或 Satis 仓库若启用了 OAuth2 或 JWT,Token 过期逻辑由服务端控制,Composer 完全无感知
如何让过期检测变成前置动作
靠 Composer 内置机制做不到。必须在 CI/CD 流程中插入轻量级校验步骤,而非等 composer install 报错才响应。
- 对 GitHub:用
curl -H "Authorization: Bearer $GITHUB_TOKEN" -I https://api.github.com/user 2>/dev/null | head -1检查返回是否为HTTP/2 200;返回401即过期 - 对 GitLab:类似,请求
https://gitlab.example.com/api/v4/user,检查200 OK - 把该命令塞进 CI 脚本,在
composer install前执行;失败则exit 1并触发告警(如 Slack webhook) - 别依赖
composer config --global github-oauth—— 它只存 token 字符串,不验证可用性
为什么 composer audit 和 allow-plugins 都拦不住授权问题
composer audit 只查 CVE,和认证无关;allow-plugins 白名单管的是插件执行权限,不涉及 auth.json 解析或 Token 校验流程。这两者都在依赖安装阶段之后或之外运行,完全不触碰凭证链。
真正起作用的只有两点:
- CI 环境变量是否注入正确(
GITHUB_TOKEN或COMPOSER_AUTH),且未被误删/截断 - auth.json 中的 token 字段是否为明文字符串(不能是环境变量引用,如
"password": "${GITHUB_TOKEN}"—— Composer 不展开 shell 变量)
另外注意:COMPOSER_AUTH 环境变量优先级高于 auth.json,但若它值为空或格式非法(如缺少 {"github-oauth": {"github.com": "xxx"}} 包裹),Composer 会静默忽略,仍去读 auth.json —— 这种“半生效”状态最难排查。
容易被忽略的细节:Token 类型与 Composer 版本兼容性
GitHub fine-grained token 在 Composer v2.2 以下根本无法解析,v2.2–v2.4 需要显式启用 github-expose-token,v2.5+ 默认禁用该 flag —— 也就是说,升级 Composer 可能突然导致私有包拉取失败,而错误信息仍是模糊的 Could not authenticate。
- 确认版本:
composer --version,低于 v2.5 的项目建议统一升级 - 检查当前策略:
composer config -g github-expose-token,输出false表示已禁用暴露 - 若必须用 fine-grained token,且不能改策略,则需在
repositories中显式声明私有包,并配"type": "vcs"+"url",绕过默认 GitHub 源的 token 注入逻辑 - 别把 Token 写死在项目根目录的 auth.json —— 它会被 Git 提交,且优先级低于全局配置,易引发混淆
最稳妥的做法是:CI 中用 COMPOSER_AUTH 注入,本地开发用 ~/.composer/auth.json,两者都只存 classic token(兼容性最强),并设置监控脚本每月自动检查 API 可达性。











