Rotating npm Publish Tokens Without Breaking CI
A leaked or expiring publish token must be replaced, but a careless rotation breaks every release pipeline that depends on it. This page shows how to rotate npm publish tokens safely with no failed publishes.
Exact symptoms and error messages
After a token is revoked but not yet replaced, release jobs fail:
npm error code E401
npm error 401 Unauthorized - PUT https://registry.npmjs.org/@acme%2fui
npm error This token has been revoked.
Root cause analysis
Publish tokens are long-lived shared secrets, so rotation is a two-sided change: the new token must be in the secret store before the old one is revoked, or there is a window where CI has no valid credential. Granular, short-lived tokens shrink that risk, and OIDC-based provenance publishing removes the standing secret entirely.
Token rotation breaks pipelines because a publish token is a long-lived shared secret with two sides that must stay in sync: the secret store CI reads from, and the registry's list of valid tokens. Revoke the registry side before the store side is updated and there is a window where CI holds a credential the registry no longer accepts — every release in that window fails. The whole risk is the ordering of those two operations.
Granular, expiring tokens shrink the window but do not remove it; the ordering still matters. The only way to remove the standing secret entirely is OIDC, where CI exchanges a short-lived identity for publish rights per job. With no long-lived token, there is nothing to rotate and nothing to leak between rotations — which is why provenance-based publishing is increasingly the recommended end state.
Resolution and configuration patch
Rotate in a safe order — create, deploy, verify, then revoke:
# 1. Mint a new granular token scoped to the package (write)
# 2. Update the CI secret (no revoke yet)
gh secret set NPM_TOKEN --body "$NEW_TOKEN"
# 3. Run a dry-run publish on the pipeline to confirm auth
npm publish --dry-run
# 4. Only now revoke the old token
Better still, move to OIDC so CI exchanges a short-lived identity for publish rights and there is no token to rotate.
Bake the safe ordering into a runbook so rotation is mechanical rather than improvised under pressure:
# 1. Mint the new granular token (write scope, package-scoped)
# 2. Update the CI secret WITHOUT revoking the old token yet
gh secret set NPM_TOKEN --body "$NEW_TOKEN"
# 3. Trigger a dry-run publish on the pipeline to confirm the new token works
gh workflow run release.yml -f dry_run=true
# 4. ONLY after a green dry-run, revoke the old token
npm token revoke <old-token-id>
The dry-run between steps 2 and 4 is the safety interlock: it proves the replacement authenticates on the real pipeline before the old credential is destroyed.
CLI validation and debug commands
# Confirm the new token authenticates before revoking the old one
npm whoami
# List active tokens to find the one to revoke
npm token list
# Revoke by id once the new token is verified live
npm token revoke <token-id>
Prevention and CI guardrails
- Always deploy the replacement secret before revoking the old token.
- Prefer granular, expiring tokens scoped to a single package over classic tokens.
- Move to OIDC/provenance publishing so there is no long-lived secret to rotate.
- Alert on token expiry so rotation is planned, not an incident response.
Moving to OIDC so there is nothing to rotate
The most durable answer to token rotation is to stop having a token. With OIDC-based publishing, the CI job proves its identity to the registry and receives short-lived publish rights for that run only. There is no secret in the store to leak, expire, or rotate — the credential exists for the duration of the job and then vanishes.
This also strengthens provenance: because the registry knows the publish came from a verified CI identity, it can attach an attestation tying the tarball to the source and build, the same guarantee described in Adding SLSA Provenance to Package Releases. Migrating is usually a matter of granting the workflow id-token: write, publishing with --provenance, and removing the standing NPM_TOKEN secret. The rotation runbook then becomes unnecessary, because the thing it protects no longer exists.
Alerting on expiry so rotation is planned
Rotation goes wrong most often when it is reactive — a token expires or leaks and someone scrambles. Making it planned means knowing an expiry is coming before it lands. Granular tokens have an expiry date, so record it and alert ahead of time rather than discovering it from a failed release.
A simple scheduled check that lists tokens and flags any expiring within, say, two weeks turns rotation into routine maintenance. Pair it with the safe ordering runbook, and rotation becomes a calm, scheduled task: the alert fires, you mint and deploy the replacement, dry-run it green, and revoke the old token — no failed pipelines, no incident. The failure mode this prevents is the 3 a.m. 'this token has been revoked' error that stops every release until someone reconstructs the correct ordering under pressure.
Frequently Asked Questions
How do I rotate with zero failed publishes?
Add the new token to the secret store and verify it with a dry-run publish before you revoke the old one. Never revoke first — that guarantees a window with no valid credential.
Can I avoid publish tokens entirely?
Largely, yes. OIDC-based publishing lets CI exchange a short-lived identity token for publish rights per job, so there is no standing secret to leak or rotate.
How do I rotate a publish token with zero failed releases?
Deploy the new token to the secret store first, prove it with a dry-run publish on the real pipeline, and only then revoke the old token. Never revoke first — that guarantees a window where CI has no valid credential.
Can I avoid publish-token rotation entirely?
Yes, with OIDC. The CI job exchanges a short-lived identity for publish rights per run, so there is no standing secret to leak or rotate — and it enables provenance attestation as a bonus.
How do I keep rotation from becoming an incident?
Alert on token expiry ahead of time and follow a fixed ordering runbook. That turns rotation into scheduled maintenance instead of a scramble triggered by a failed release.
Related
- Private Registries and Access Control — the overview for private distribution and access control.