Safeguard
DevSecOps

npm CLI Login in CI: Tokens, npm-cli-login, and Safer Patterns

The npm-cli-login package automated interactive npm login for CI pipelines — a pattern that npm's 2025 authentication overhaul has made both broken and unnecessary. Here is what to use instead.

Karan Patel
Platform Engineer
7 min read

The npm-cli-login package exists to script the interactive npm login prompt for CI environments — and after npm's late-2025 authentication overhaul, you should not be using it, because username-and-password logins in automation are exactly the pattern the registry is engineering away. If you searched for npm login cli automation because a pipeline just broke, the good news is that every use case it served now has a first-class, safer replacement. This post covers what changed, why the old pattern was always risky, and the three patterns that work today.

Why npm login Never Fit CI

npm login is interactive by design: it prompts for username, password, and a second factor, then writes a credential to ~/.npmrc. CI jobs cannot answer prompts, so the ecosystem grew workarounds — npm-cli-login (an npm package that drives the prompts programmatically), expect scripts, and piped heredocs.

All of them shared the same flaw: they required storing a real npm password in CI secrets. A password is the master credential for the account — it can change email addresses, disable 2FA in some flows, create tokens, and publish anything. Any CI log leak, compromised runner, or malicious workflow step that read it owned the account outright. Token-based auth was always the better answer; the login-automation packages persisted mainly because old tutorials kept recommending them.

What Changed in Late 2025

The npm registry's response to 2025's supply chain attacks — most visibly the September phishing compromise of high-download maintainers and the Shai-Hulud self-replicating worm that spread via stolen publish credentials — was to shorten the lifetime of every credential class:

  • Classic tokens are gone. Creation was disabled on November 5, 2025, and all existing classic tokens were permanently revoked on December 9, 2025. If a pipeline is failing with an auth error this quarter, this is the likely reason.
  • npm login now issues a two-hour session token. Interactive logins no longer mint long-lived credentials, which kills the npm cli login automation pattern outright — even if you script the prompts, the resulting credential dies within two hours.
  • Granular access tokens got tighter defaults. New write-enabled tokens default to a 7-day lifetime with a hard maximum of 90 days, and enforce 2FA on publish by default (with an explicit bypass option intended for CI).
  • Local publishes prompt for 2FA. Human publishes are interactive by default; automation is expected to use granular tokens or OIDC.

The direction is unambiguous: no more immortal secrets. Your CI auth strategy needs to assume rotation.

Pattern 1: Granular Token via Environment Variable

The workhorse pattern. Create a granular access token scoped to only the packages your pipeline publishes (or read-only, if the job just installs from a private registry), then reference it from an environment variable — never write the literal token to a file in the repo:

# .npmrc (committed — contains no secret)
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
# GitHub Actions step
- run: npm publish --access public
  env:
    NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Rules that keep this pattern safe:

  1. Scope minimally. One token per pipeline, limited to the specific packages and permission (read vs. read-write) it needs. A read token for npm ci should not be able to publish.
  2. Treat the 90-day cap as a feature. Put token expiry on the calendar or, better, automate rotation. An expired-token build failure is annoying; it is also proof the blast radius of a leak is now bounded.
  3. Never echo .npmrc in CI logs, and keep .npmrc files with real tokens out of Docker images — a token baked into an image layer survives image distribution. Use build secrets (docker build --secret) instead of ARG/ENV.

Pattern 2: Trusted Publishing (Kill the Token Entirely)

For publishing from GitHub Actions or GitLab CI/CD, OIDC trusted publishing is now the strongest option and the one npm itself recommends. The workflow authenticates with a short-lived, workflow-bound OIDC credential exchanged automatically at publish time. There is no stored secret to steal, rotate, or accidentally print:

permissions:
  id-token: write
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 ci
      - run: npm publish --provenance --access public

Configure the trusted publisher once in the package settings on npmjs.com (repository, workflow filename, optional environment). Add --provenance while you are there — the signed build attestation is nearly free at this point. We walk through the full release setup in our guide to creating and publishing npm packages securely.

The main current limitation: OIDC support covers GitHub Actions and GitLab CI/CD, with other providers on npm's roadmap. Jenkins, Buildkite, and friends still need Pattern 1.

Pattern 3: Private Registries and Proxies

If your CI authenticates to Artifactory, Verdaccio, GitHub Packages, or another private registry, the same principles apply with registry-specific mechanics — scoped registry lines in .npmrc, short-lived credentials where the platform supports them:

@yourorg:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

GitHub Packages is the pleasant case: the ephemeral, automatically-issued GITHUB_TOKEN works for both installs and publishes within the same org, giving you rotation for free.

Auditing What You Have Now

Most teams accumulated npm credentials over years. A one-hour audit pays for itself:

# List tokens on your account (also manageable from npmjs.com settings)
npm token list

Hunt for stragglers in the usual places: CI secret stores, ~/.npmrc on shared build machines, Dockerfiles, shell scripts in ops repos, and .npmrc files accidentally committed with literal tokens (grep for _authToken=npm_). Revoke anything unscoped or unexplained. Compromised publish credentials are how registry worms propagate — every stale token is standing attack surface, which is why continuous monitoring of your dependency supply chain matters as much as your own publish hygiene; platforms like Safeguard flag when a package you depend on ships a suspicious release, whoever's token signed it.

Migration Cheat Sheet

If you have...Move to...
npm-cli-login or scripted npm loginGranular token via ${NPM_TOKEN}, or OIDC
Classic token in CI secretsAlready revoked — granular token or OIDC
Granular token, no expiry planCalendar the 90-day rotation or automate it
GitHub Actions / GitLab publish jobTrusted publishing + --provenance
Password stored anywhere automatedDelete it, rotate the password, enable phishing-resistant 2FA

FAQ

What was npm-cli-login for?

It programmatically answered the interactive npm login prompts so CI jobs could authenticate with a username and password. It dates from an era when some registries only supported password auth; against npmjs.com today it is obsolete, and the two-hour session tokens issued by modern npm login make the approach useless for pipelines anyway.

How do I do an npm login from the CLI in CI today?

You do not log in at all. Provide a granular access token through an environment variable referenced in .npmrc (_authToken=${NPM_TOKEN}), or configure OIDC trusted publishing so the CI platform proves its identity without any stored secret.

Why do write tokens expire after 90 days now?

npm capped granular write-token lifetimes (7-day default, 90-day maximum) in October 2025 after multiple incidents where long-lived stolen tokens were used to publish malware. Short lifetimes bound how long a leaked credential is useful.

Is trusted publishing worth it for a small internal package?

If it publishes from GitHub Actions or GitLab CI/CD, yes — setup is a one-time form on npmjs.com and it deletes an entire category of secret management. For other CI systems, a tightly scoped granular token with scheduled rotation is the current best practice.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.