Next.js 16.3.2 换掉 CI 里的长期令牌:Turborepo 远程缓存认证改为 OIDC
2026 年 8 月 21 日发布的 Next.js 16.3.2 把仓库 CI 里 Turborepo 远程缓存的认证方式,从长期有效的静态 PAT 换成了每次任务临时签发的 OIDC 令牌。本文拆解 PR
一个藏在发布说明里的安全改造
2026 年 8 月 21 日,Next.js 发布 v16.3.2。这只是一个 LTS backport 修复版,六项 Core Changes 里五项是 Turbopack 与路由问题,看起来平平无奇。但其中一条值得单独读一遍:
Authenticate Turborepo remote caching with OIDC instead of a static PAT (#97603)
这句话的意思是:Next.js 自己的 GitHub Actions CI,不再用仓库里存放的长期 Personal Access Token 去连接 Vercel Remote Cache,而是改为每个 job 用 GitHub OIDC 令牌换取短时访问令牌。由 @eps1lon 在 PR #97590 中完成,随后 backport 到 16.3.x 分支,随本次补丁发布。
对使用 Turborepo 远程缓存的团队来说,这是官方项目带头示范的一次"CI 凭据最小化"改造:把仓库 secrets 里的长期令牌,换成按次签发、只给缓存权限的短时令牌。
背景:远程缓存的两种认证方式
Turborepo 的远程缓存让团队和 CI 共享构建产物,避免同一任务在每台机器上重复执行。托管在 Vercel 上的 Remote Cache 一直有两种认证方式:
- Personal Access Token(PAT):长期有效、按团队成员身份签发的令牌,作为
TURBO_TOKEN存进 CI 的 secrets。 - OpenID Connect(OIDC):CI/CD 提供商(如 GitHub)用 OIDC 令牌向 Vercel 换取短时 Turborepo 访问令牌,设置到
TURBO_TOKEN环境变量。
2026 年 7 月 30 日,Vercel 在 官方 changelog 中宣布 OIDC 支持上线,并明确给出三个对比点:
- OIDC 令牌是短期的,而 PAT 是长期有效的;
- OIDC 令牌只授予 Vercel Remote Cache 访问权限,范围更窄;
- OIDC 令牌与 Vercel team 关联,而不是与某个团队成员绑定。
官方当时的建议就是:所有客户把 CI/CD 工作流从 PAT 迁移到 OIDC。
PR #97590 的自述:长期 PAT 的三个问题
Next.js 团队自己的 CI 此前用的就是 TURBO_TOKEN 仓库 secret。PR #97590 的描述直白地列出了它不满意的三点:
- 令牌永不过期:长期 PAT 没有自然的轮换周期,泄露后影响面持续存在;
- 绑定成员而非团队:令牌与具体团队成员的身份绑定,人员离职、权限变更时容易留下悬挂凭据;
- 可见面过大:放在仓库 secrets 里,所有继承 secrets 的 job 都能读到它,即使某个 job 根本不需要远程缓存。
改造后的行为是:每个 job 通过 vercel/setup-turborepo-remote-cache-action 请求 GitHub OIDC 令牌,向 Vercel 上配置的 Turborepo CLI OIDC 策略换取自己的短时缓存令牌。令牌按 job 签发、只访问 Remote Cache、随任务结束失效。
迁移怎么做:三步配置
对普通团队来说,把 CI 从 PAT 换成 OIDC 只需要在 Vercel 和 GitHub 两侧各做一次配置,然后改一行 workflow。官方文档(Use Remote Caching from external CI/CD)给出了完整流程:
第一步:在 Vercel 创建 Turborepo CLI OIDC 策略
进入团队的 Settings → Build and Deployment → OIDC Policies for CLI Access,添加一条 Turborepo CLI 策略。如果 CI/CD 提供商在列表里(GitHub 就在其中),直接选择对应的 GitHub 账户和仓库;也可以手动配置 OIDC issuer 和 claims。策略可以进一步限定到某个 workflow 或分支,并自定义 audience。
第二步:设置 TURBO_TEAM 仓库变量
TURBO_TEAM 是 Vercel 团队 slug(团队 URL 中 vercel.com/ 后面的部分)。官方建议用仓库 variable 而不是 secret 存放,因为 GitHub 不会对日志里的 variable 做打码,团队名在 CI 日志里保持可读:
gh variable set TURBO_TEAM --body "your-team-slug"
第三步:在 workflow 里换上 setup action
在运行 turbo 的步骤之前加入 vercel/setup-turborepo-remote-cache-action。它负责请求 GitHub OIDC 令牌、向 Vercel 换取短时 Turborepo 访问令牌,并设置 TURBO_TOKEN 和 TURBO_TEAM 供后续步骤使用。关键前提是 job 需要声明 id-token: write 权限:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set up Turborepo Remote Cache
uses: vercel/setup-turborepo-remote-cache-action@v1.0.0
with:
team: ${{ vars.TURBO_TEAM }}
# ... 后续运行 turbo 的步骤
如果团队配置了多条 OIDC 策略且可能同时匹配,还需要在 policy 输入里显式指定要用的策略 ID。
边界与回退:这次改造的取舍
PR #97590 还披露了两个值得注意的工程决策:
- fork 仓库直接跳过:fork 没有访问仓库 variables 的权限,因此该步骤在 fork 的 CI 里会被跳过,避免 fork 提交 PR 时因缺少配置而失败。
- 失败时静默降级:步骤设置了
continue-on-error式的容忍——在服务故障或权限异常时,步骤结果被忽略,CI 回退到无远程缓存的行为。作者也承认这可能导致"静默回归":远程缓存悄悄失效,而 CI 仍然全绿。原仓库计划通过监控补上这块盲区。
对迁移中的团队,这意味着:OIDC 换完后不能只看 CI 是否通过,还要确认日志里真的出现了 remote cache hit,否则可能在不知情的情况下丢掉了缓存收益。
团队切换前检查什么
- 确认 Vercel 侧 OIDC 策略已生效:先在本地或临时 workflow 里跑一次带
--verbosity=2的 turbo 命令,观察令牌交换是否成功。 - 清理旧 PAT:迁移完成后,删除仓库 secrets 里的
TURBO_TOKEN,并去 Vercel 撤销对应的长期令牌;不要只加新认证而不回收旧凭据。 - 检查缓存命中:CI 日志里确认出现 remote cache hit/upload,而不是每次都 miss。
- 限制策略范围:OIDC 策略尽量限定到具体仓库、workflow 和分支,缩小令牌可被滥用的面。
- 注意多策略场景:配置了多条匹配策略时,在 action 里显式传入
policyID,避免匹配歧义。
Next.js 16.3.2 本身只是一个小补丁,但它示范了一件事:即使只是"读缓存的 CI 凭据",也值得用短期、窄权限的令牌替代长期共享 secret。这套模式同样适用于其他支持 OIDC 的缓存与部署服务——把"永不轮换、人人可见"的凭据,换成"按需签发、用完即弃"的短时令牌。
(内容由AI生成,仅供参考)