As of December 9, 2025, npm classic tokens are gone for good. If your pipelines still depend on them, you’ve already felt the pain: publish jobs failing, weekend releases blocked, and rushed hotfixes. The headline you need to act on is simple—npm classic tokens revoked—and the fix is to move to either OIDC-based trusted publishing or short‑lived granular access tokens. Here’s the practical path to both, plus the sharp edges teams are hitting this week and how to avoid them.
What exactly changed on December 9, 2025?
Three major changes landed at once:
First, classic tokens—those long‑lived npm tokens many of us stashed in CI years ago—were permanently revoked. Second, session‑based authentication became the default for interactive users: npm login issues two‑hour session tokens, and you’ll re‑authenticate for protected operations like publish. Third, the npm CLI now supports creating and managing granular access tokens from the terminal, removing a longstanding friction point that forced web UI clicks for token maintenance. Bonus: new packages skew secure‑by‑default with 2FA turned on from day one, and a legacy auth endpoint (used by older tooling, notably Yarn v1/v2) is temporarily restored but slated for removal.
If you missed the earlier milestones: classic token creation was disabled November 5, and write‑scoped granular tokens are capped at 90 days with 2FA defaults and a CI‑friendly “Bypass 2FA” option. The message is clear—short‑lived, scoped, and verifiable credentials are now the norm.
npm classic tokens revoked: what breaks and why
Any pipeline that publishes to npm with an old NPM_TOKEN now fails authentication. That includes GitHub Actions, GitLab CI, Jenkins, CircleCI, Buildkite, and bespoke runners. If you’re running Yarn v1/v2 flows that secretly rely on the legacy CouchDB-style user endpoint during auth, you may see intermittent success for a short window—but that endpoint is on borrowed time. Treat any residual success as luck, not a solution.
Local developers aren’t spared. Your npm publish will prompt more often, and if you haven’t enabled phishing‑resistant 2FA yet, expect friction until you do. On the upside, session tokens never linger in your shell history or dotfiles, and they don’t show up in your token lists—less for attackers to steal.
Choose your path: trusted publishing vs. granular tokens
There are two viable routes, and you can mix them in a monorepo.
Path A: Trusted publishing (OIDC) — Best for GitHub Actions or GitLab.com shared runners. Your workflow presents an OIDC identity to npm at publish time; npm issues a one‑time, short‑lived token bound to that workflow. No long‑lived write tokens to rotate or leak, and npm generates provenance attestations automatically for public packages from public repos. This is the security‑first default going forward.
Path B: Granular access tokens — Best for other CI providers or stopgaps while you rewire. You create a scoped token with the minimal permissions needed, enable “Bypass 2FA” for non‑interactive CI, and set a short expiration (expect a hard 90‑day maximum for write). Store in a proper secret manager and script rotation. It’s not as strong as OIDC, but it’s workable and predictable.
GitHub Actions: minimal trusted publishing workflow
This is the smallest working example I’ve set up this week for teams migrating from classic tokens. Note the id-token: write permission and the absence of NODE_AUTH_TOKEN during publish:
name: Publish
on:
push:
tags:
- 'v*'
permissions:
id-token: write
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: npm install -g npm@latest
- run: npm ci
- run: npm test --if-present
- run: npm publish
Be sure to register this specific repository and workflow file as a trusted publisher in your package’s npm settings. If you publish multiple packages from one repo, that’s fine—trust is tied to the workflow, not a single package.
GitLab CI: trusted publishing with OIDC
GitLab’s shared runners can also present OIDC to npm. Here’s a trimmed example:
stages: [test, publish]
variables:
NODE_VERSION: '20'
test:
stage: test
image: node:${NODE_VERSION}
script:
- npm ci
- npm test
publish:
stage: publish
image: node:${NODE_VERSION}
id_tokens:
NPM_ID_TOKEN:
aud: "npm:registry.npmjs.org"
script:
- npm install -g npm@latest
- npm ci
- npm publish
only:
- tags
As with Actions, bind this pipeline to your package as a trusted publisher in npm settings.
Jenkins, CircleCI, Buildkite, and others
Use granular tokens while you evaluate OIDC options. Create a write‑scoped token with Bypass 2FA enabled, set a short expiration (30–60 days), and store it in your secret manager. Expose it only for the publish step:
steps:
- command: npm ci
- command: npm test
- command: npm publish
env:
NODE_AUTH_TOKEN:
Then schedule auto-rotation and alert on failures. Treat these tokens like nitroglycerin: scoped, short‑lived, tightly guarded.
Fast 60‑minute audit: find and replace dead tokens
Here’s a quick incident‑style sweep we’ve run with several teams this week.
- Inventory where publishing happens. Search for
NPM_TOKEN,NODE_AUTH_TOKEN, andnpm publishacross build pipelines, GitHub Actions, GitLab, Jenkins, and release scripts. - Find classic tokens by behavior, not just name. Even if you labelled a secret “granular”, it may still be classic. If publish fails with 401/403 immediately after December 9, assume it’s classic until proven otherwise.
- Map repos → packages → workflows. For each published package, decide Path A (OIDC) or Path B (granular), and document the owner responsible for credentials.
- Enable phishing‑resistant 2FA for maintainers. FIDO/WebAuthn keys reduce account‑takeover risk during emergency rotations.
- Monorepo nuance. If your release tooling loops through workspaces, ensure the trusted publisher workflow actually triggers for each package—or hoist publishing into one canonical job.
- Yarn v1/v2 edge case. If your auth flows rely on the legacy CouchDB‑style endpoint, plan to move off it now; it’s only temporarily restored. Prioritize upgrading your package manager or switching to npm CLI for publish.
Why this shift? Follow the attacks, not the vibes
The deprecation timeline didn’t happen in a vacuum. The JavaScript ecosystem took several body blows this fall: worm‑style malware campaigns that abused maintainer credentials, widespread exfiltration of GitHub PATs and cloud keys, and a November second wave that touched popular orgs and community maintainers. When one long‑lived token leaks—via logs, a compromised runner, or a phished maintainer—attackers get durable write access and move fast. Short‑lived, scoped, and verifiable credentials slam that window shut.
Trusted publishing also brings provenance. For public packages published from public repositories, npm now emits cryptographic attestations showing where and how a package was built. Consumers can verify that what they install was built by the workflow you intended. It’s a meaningful step toward taming the sprawl of opaque build chains.
People also ask: quick answers
Are session tokens replacing granular tokens?
No. Session tokens are for interactive sessions after npm login. CI should use either OIDC trusted publishing or granular tokens. Don’t try to shoehorn session tokens into automation—they expire in two hours and aren’t exposed to your CLI as reusable secrets.
Do I still need 2FA with trusted publishing?
For the human account, yes—enable phishing‑resistant 2FA. For the workflow, OIDC replaces the need for a reusable write token, and npm enforces the trust you configured at publish time.
What if I publish private packages from a private repo?
Trusted publishing still works for the publish itself, but automatic provenance is limited to public‑from‑public. For installing private dependencies during CI, use a read‑only granular token limited to your org scope.
Will tokens expire mid‑publish?
Granular tokens respect their configured lifetime; a single publish should be far shorter than that. Session tokens expire after two hours of inactivity; if you’re actively publishing locally, expect to re‑authenticate when crossing that boundary. OIDC tokens are minted just‑in‑time for the publish and expire promptly afterward.
Can I keep using classic tokens for installs only?
No—classic tokens are revoked across the board. Use read‑only granular tokens for installs in CI where needed, and keep them scoped and short‑lived.
Security tradeoffs and gotchas teams are hitting
Self‑hosted runners. Today’s trusted publishing support targets GitHub‑hosted and GitLab.com shared runners. If you’re self‑hosting, use granular tokens for now or run a small, isolated hosted runner pool for your publish job.
Wrong workflow name. The workflow filename you register with npm must match exactly, including case and extension. If you use workflow_call chains, npm validates the caller workflow name, which trips teams up.
Monorepos with tags. If you tag per package (v-pkg-a-1.2.3) ensure your trigger pattern matches, or centralize versioning with a release tool that emits a single tag and loops packages.
Private dependencies during publish. Trusted publishing authenticates publish, not npm ci for private deps. Use a separate read‑only token for installs, scoped to the org and expiring fast.
2FA defaults for new packages. New packages now start with 2FA on by default. That’s good—but expect your first publish to prompt maintainers who haven’t enrolled. Plan a short onboarding step with security keys for new repos.
A pragmatic 48‑hour migration plan
Here’s the shortest path I recommend for most orgs.
- Day 0 (today): Triage failures, pick a path per package (OIDC where possible), and communicate the plan to maintainers. Freeze non‑critical releases for 24 hours.
- Hour 0–4: Enable phishing‑resistant 2FA on maintainer accounts. Create a dedicated “release” team with least‑privilege package access. Document owners.
- Hour 4–12: For GitHub/GitLab packages, set up trusted publishing and test a dry‑run publish on a pre‑release tag. For everything else, mint short‑lived granular write tokens with Bypass 2FA and swap them into CI only for the publish step.
- Hour 12–24: Ship a single patch release through each new workflow. Validate provenance for public packages, verify that only the registered workflow can publish, and remove any leftover classic token references.
- Day 2: Turn on alerting: failed publish alarms, token‑nearing‑expiration alarms, and provenance‑missing alarms. Schedule auto‑rotation for granular tokens at 60‑day intervals and audit quarterly.
Policy meets practice: how we coach teams through this
When we help teams recover from registry incidents, two patterns stand out. First, orgs that simulate a publish failure and practice rotating credentials sail through days like December 9. Second, orgs that treat package publishing as “just another job” without owner accountability are the ones who spend a weekend in incident mode. Create ownership. Make the “release engineer” a role with rotation and backup, not a hope and a prayer.
If you need a structured security playbook to run in parallel, our incident‑driven guides like React2Shell: Patch, Prove, Prevent and the Next.js CVE‑2025‑66478 patch‑and‑prove playbook show how to verify fixes, detect misuse, and harden for the long term. And if uptime matters while you rewire auth, review how to ship fixes without going down.
Reference configuration: mixing OIDC and tokens in a monorepo
Many enterprises need both paths. For example: public OSS packages use OIDC; internal packages published from a self‑hosted system use granular tokens. Keep them separate and explicit:
- Folder‑level workflows. Place
.github/workflows/publish-oss.ymlwith OIDC trust for OSS folders. Placepublish-internal.ymlthat readsNODE_AUTH_TOKENfrom org secrets for internal folders only. - Tag strategy. Use
v*for OSS,internal/*for internal publishes. Reduce the chance a token leaks into the wrong job. - Access boundaries. Scope granular tokens to a single org or even a single package where possible. Don’t mint “super tokens.”
What to do next
- Pick OIDC trusted publishing wherever you can; it’s safer and lower‑maintenance than any token strategy.
- For non‑supported CI, adopt granular tokens with short expirations and automated rotation.
- Enable phishing‑resistant 2FA for all maintainers and enforce 2FA on packages and orgs.
- Instrument your pipelines: alert on failed publishes, missing provenance, and tokens within 10 days of expiry.
- Schedule a quarterly “supply‑chain fire drill.” Rotate tokens, fail a runner on purpose, and watch your alerts fire.
- If you want hands‑on help getting this done without breaking a release, our security engineering services and contact page are a good place to start.
Zooming out
This change is overdue, and it will save real incidents. The npm ecosystem needed a decisive break from long‑lived write tokens after multiple waves of compromise this year. Yes, there’s short‑term friction—especially for older build systems and teams juggling self‑hosted runners. But once you stand up OIDC for publish and reserve granular tokens for legacy edges, you’ll spend far less time chasing down leaked secrets and more time shipping. That’s a trade I’ll take every day.
If you’re rebuilding pipelines and want a battle‑tested approach to change management in production, our broader engineering guidance on the ByBowu blog is built for exactly these moments—move fast, verify, and harden as you go.