JavaLYG

GitHub CLI短期令牌过期后脚本报401:用按需刷新替代缓存Token

脚本早上还能调用 GitHub,过几个小时突然报 401;重新取一次令牌又好了。如果你准备启用 GitHub CLI 的短期 OAuth 凭据,先检查脚本是否把 Token 存成了长期配置。下面按 gh 2.103.0 的新能力,拆开按需刷新、HTTPS Git 凭据和环境变量三条边界,并给出不登录的本地自检。

一、更新了什么,没更新什么

GitHub 在 2026 年 10 月 21 日公告:CLI 从 v2.103.0 起提供可选的、自动刷新的短期 OAuth 凭据,目前为公开预览。它保存短期 access token 和轮换的 refresh token,需要时用后者换取新的访问令牌。不是启动一个永远在线的“续命服务”。[1][2]

这是主动选择,不会把所有旧登录、PAT 或脚本里的字符串批量改成短期令牌。--expiring 表达申请偏好,最终要看服务端支持;不支持时可以回退到不自动过期的普通令牌。公告列出 github.com、ghe.com 已支持,GHES 从 3.23 起支持。不能只凭命令退出 0 判断拿到了哪一种。

二、先核对客户端,别让旧命令背锅

gh --version
git --version
gh auth login --help

先在登录帮助里确认真的存在 --expiring。单独核对新开关的版本,比看到“电脑装了 gh”可靠。本文读取了官方 Release 与认证文档,也下载官方 Linux amd64 发布归档、核对同站校验和,再在隔离 HOME 和配置目录运行二进制;这属于有限来源核验,不是完整杀毒认证。

本次运行的是 gh 2.103.0,Git 为 2.27.0。GitHub 推荐 HTTPS 场景使用 Git 2.46 或更新版本,便于标记短期凭据,避免缓存超过有效期;旧 Git 不等于完全不能用,但需要升级和缓存行为核验。本文没有把本机旧 Git 说成已满足推荐配置。

三、登录和 Git 必须走同一条凭据路径

下面是读者确认影响后自行执行的登录流程,会涉及账户授权和 Git 凭据配置,不属于本文已经完成的远程验收。运行前检查是否存在环境变量令牌覆盖,勿在共享日志里打印值。

# 以下是真实登录步骤,需要本人授权;不是离线自检。
gh auth login --hostname github.com --git-protocol https --expiring
gh auth status --hostname github.com
gh auth setup-git --hostname github.com

最后一步将指定主机的 HTTPS Git 凭据交给 gh。只改登录、不改原来保存静态令牌的 helper,Git 仍可能拿着旧字符串。该命令会修改 Git 配置,应先确认现有多账户或企业 helper 的安排;SSH 认证也不会因此自动迁移成 OAuth。

想让后续登录默认表达短期偏好,可以用 gh config set expiring_credentials enabled,再用 gh config get expiring_credentials 读回。这个设置不会独自完成授权,也不会转换已有 PAT。增加权限与自动续期不是同一动作;需要重新授权时显式保留短期偏好,并按当前版本帮助确认行为。[3]

四、为什么缓存一次 Token 迟早会踩空

常见错误是运行一次 gh auth token,把结果写入配置文件,之后每次任务都复用这份文本。字符串不会因为 gh 在别处刷新了凭据,就自己变成新值。工具链只剩旧票据时,故障可能发生在下一次请求,而不是配置保存的那一刻。

能直接使用 gh api 的地方,优先让 gh 完成请求。确需交给其他客户端时,在每次需要令牌时重新通过 gh 获取,并处理失败,不缓存到长期文件;也别把命令输出贴进工单、打开 Shell 跟踪或放进可见参数。短期有效不代表泄露可以忽略,refresh token 同样是敏感凭据。

这一点还有明确例外:通过 GH_TOKEN 或 GITHUB_TOKEN 提供的令牌不会被 gh 自动刷新。[2] 它们可由人工、CI 或外部密钥系统注入,生命周期由外部管理;变量存在时还可能优先于本机保存凭据。切换登录方式前,先查实际来源,不要把变量里的 PAT 当成 OAuth 刷新令牌。

gh托管的可刷新OAuth与环境变量令牌是两条不同凭据路径
上排限定已经取得可刷新凭据;下排包含自动化注入,不仅是人工输入。图示不保证刷新、授权或业务操作成功。DM-Fox生成与编辑,标题做精确文字后处理,等比例补边,经技术与可读性复核。

五、不碰账户,也能先验配置开关

将下面完整代码保存为 Shell 脚本,用 Bash 执行。它要求 PATH 中已有 gh 2.103.0+,只创建并清理自己的临时配置目录,不登录、不请求仓库;两次设置都发生在临时 gh 配置里,退出后不改变你的日常偏好。这是配置隔离,不是操作系统安全沙箱。

#!/usr/bin/env bash
set -eu
# 只创建临时配置,不登录、不访问仓库,也不触碰现有登录态。
work=$(mktemp -d)
trap 'rm -rf -- "$work"' EXIT
export GH_CONFIG_DIR="$work/gh"
export GIT_CONFIG_GLOBAL="$work/gitconfig"
export GIT_CONFIG_NOSYSTEM=1
mkdir -p "$GH_CONFIG_DIR"
gh --version
git --version
gh auth login --help | grep -- --expiring
gh config set expiring_credentials enabled
test "$(gh config get expiring_credentials)" = enabled
gh config set expiring_credentials disabled
test "$(gh config get expiring_credentials)" = disabled
test ! -e "$GH_CONFIG_DIR/hosts.yml"
printf '本地开关读回通过;未创建账户凭据。\n'

本次额外做了 19 项本地检查,包含开关帮助、默认值、开启/关闭读回、非法值拒绝、未登录失败及合成环境变量的读取。随文脚本只覆盖其中的最小路径,没有交付整个内部测试夹具,也没有使用真实 OAuth 或仓库写权限来凑“亲测”。

六、401 不是“刷新坏了”的同义词

现象先查什么不要直接下结论
不认识 --expiringgh 实际版本、PATH 指向装过 gh 不等于新开关可用
登录后仍读到旧令牌环境变量覆盖、主机、当前账户重登不保证请求改走新凭据
gh 可用,Git HTTPS 失败目标 URL、helper、Git 版本与缓存gh 登录成功不证明 Git 已接管
运行一阵后报 401是否缓存令牌、撤销、主机和刷新错误不能只凭 401 认定自然到期
能读公开资源,写操作失败资源授权、所需权限、组织限制匿名可读不证明写权限

默认 gh auth status 可能在报告状态时刷新临近过期的可刷新凭据,不是绝对无副作用的观察。需要禁止自动刷新时可看 --no-refresh,但这也不等于离线或业务验收。不要为“修复”401 无限重试,更不要自动扩大权限;先留脱敏错误,再区分网络、凭据与资源授权。

七、验收要分四层,不是一句登录成功

  • 客户端层:版本与开关存在,配置写入后能读回。
  • 身份层:目标主机、账户和实际凭据类型正确;服务端回退要被发现。
  • 接入层:HTTPS Git 确实走预期 helper;外部客户端不复用过期文本。
  • 业务层:对目标资源执行所需最小操作并核对结果,公开读取不能证明受保护写权限。

本文只完成第一层和本地合成输入验证,没有执行真实授权、跨到期刷新、Git 拉推或组织权限测试。生产迁移应先在受控账户验证,再调整任务;关闭偏好也不等于撤销现有凭据,回退和撤销分别处理。

八、官方依据与适用边界

资料核对日期为 2026 年 10 月 22 日。预览功能和帮助页可能继续变化;以受检版本及目标服务的实际结果为准。核心不是“令牌再也不过期”,而是让真正持有刷新能力的组件负责取新值,别把会变化的凭据冻成一张旧便签。

  1. GitHub 10 月 21 日更新公告
  2. GitHub CLI v2.103.0 Release
  3. GitHub CLI 官方认证文档

🔕 评论已关闭