Plainwork

Plainwork / CI OIDC Atlas / npm trusted publishing: CI setup and ENEEDAUTH fixes

npm trusted publishing: which CI platforms work, the fields each one needs, and why ENEEDAUTH happens

npm trusted publishing lets a CI job publish a package with a short-lived OIDC token instead of a stored npm token. It works only on a short list of platforms, and the setup form asks for different fields on each. Most failures come from a mismatch between those fields and the real workflow, and npm does not tell you at save time. This page collects what npm's documentation (read on 13 Oct 2026) says, side by side, with the PyPI and RubyGems equivalents.

Which CI platforms npm supports

npm's page says trusted publishing "currently supports" GitHub Actions (GitHub-hosted runners), GitLab CI/CD pipelines (GitLab.com shared runners) and CircleCI (CircleCI cloud). It adds: "Self-hosted runners are not currently supported but are planned for future releases." So Jenkins, Bitbucket Pipelines, Buildkite, self-hosted GitLab and self-hosted GitHub runners cannot use it yet; those pipelines still need a token.

What each platform has to supply

PlatformRequired fields on npmjs.comOptionalWhat the job must do
GitHub ActionsOrganization or user, repository, workflow filename (filename only, with .yml or .yaml; the file must be in .github/workflows/)Environment nameGrant id-token: write
GitLab CI/CDNamespace, project name, top-level CI file path (for example .gitlab-ci.yml)Environment nameDeclare id_tokens with aud: "npm:registry.npmjs.org"
CircleCIOrganization ID, project ID, pipeline definition ID (all UUIDs), VCS origin such as github.com/myorg/myrepoContext IDsSet NPM_ID_TOKEN from circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}'

Each package can have up to 10 trusted publishers at once, for example one per provider. An existing connection cannot be edited: delete it and create a new one.

The GitLab audience is not the default

GitLab's default aud is the instance domain (see our GitLab id_tokens guide). npm wants npm:registry.npmjs.org, and its example also declares a second token with aud: sigstore for provenance. npm's note says: "Don't forget to configure id_tokens 'aud' to "npm:registry.npmjs.org" in your GitLab pipeline." A job that keeps the default audience gets a token npm will not accept.

publish:
  stage: publish
  id_tokens:
    NPM_ID_TOKEN:
      aud: "npm:registry.npmjs.org"
    SIGSTORE_ID_TOKEN:
      aud: sigstore
  script:
    - npm ci
    - npm publish

(Trimmed from npm's own example; the stage name is ours.)

Why you get "Unable to authenticate" (ENEEDAUTH)

npm's troubleshooting section lists these causes. Work through them in order:

  1. Workflow filename differs from the form. It must match exactly, including the extension, and "all fields are case-sensitive and must be exact".
  2. Wrong runner type. Only GitHub-hosted runners, GitLab.com shared runners or CircleCI cloud work.
  3. GitHub only: no id-token: write. Without it the job cannot get an OIDC token at all.
  4. GitHub only: repository.url in package.json does not match the repository. npm says it must match "exactly", and that this also breaks publishing from forks that kept the original value.
  5. GitHub only: a reusable or manually triggered workflow. npm says that with workflow_call or workflow_dispatch, validation checks "the calling workflow's name instead of the workflow that actually contains the publish command". Register the calling workflow's filename, and give id-token: write to both parent and child.
  6. CircleCI: an ID is wrong. Re-copy the organization, project and pipeline definition IDs from CircleCI's settings pages.
  7. The first publish was never completed. npm says a new configuration must complete its first successful publish within 2 days or it expires and "can no longer be used or edited". Delete it, create it again and publish within the window.

npm also warns that it does not verify the configuration when you save it, so "errors will only appear when you attempt to publish".

Things that surprise people after it works

  • Installing is not covered. Trusted publishing is "not intended for npm install". If npm ci needs private packages, npm recommends a read-only granular token for the install step only.
  • Provenance. From GitHub Actions or GitLab CI/CD, npm generates provenance by default, but only for public repositories and public packages. CircleCI publishes carry no provenance, and private repositories get none even for a public package.
  • Allowed actions. Each publisher can be limited to npm stage publish, with a maintainer approving through 2FA, or also allowed to run npm publish and npm dist-tag. Configurations created before 20 May 2026 allow npm publish only; ones created after 3 Sep 2026 default to staged publishing. Check which kind you have.
  • Old tokens stay valid until you act. npm suggests setting the package to "Require two-factor authentication and disallow tokens" once the OIDC path works, then revoking leftover automation tokens. It says this setting does not affect trusted publishers.

PyPI and RubyGems compared

RegistryHow it is set upCredential the registry mints
npmPer package; provider-specific fields as aboveThe npm CLI exchanges the OIDC token itself at publish time
PyPITrusted publisher on a project; PyPI says it trusts "a particular configuration on a particular CI service"A project-scoped API token "only valid for 15 minutes from time of creation"
RubyGemsOwner, repository and workflow file name for GitHub Actions, plus an optional environment; one publisher per workflowShort-lived API tokens scoped to push only to that gem

The pattern is the same everywhere: the registry stores what a good token looks like (repository, workflow, sometimes environment) and compares it with the claims in the job's token. If the job's real workflow name, environment or audience differs from what you typed into the form, publishing fails.

Check the token before you publish

If the job can print its token claims, paste the decoded payload into the OIDC token debugger. It runs in your browser and sends nothing. Compare the aud, repository and workflow values with your form. For AWS or Azure trust policies written against the same tokens, see the six-step checklist and the GitHub sub claim guide. The CI OIDC Atlas ($12) covers eleven CI platforms with the vendor sentence behind each cell, including the registry rules above.

Sources read 13 Oct 2026: npm Docs, "Trusted publishing for npm packages"; PyPI Docs, "Trusted Publishers: Getting Started"; RubyGems Guides, "Trusted Publishing". Registries change these rules often; re-read the current page before relying on a detail.

More from the catalogue

Other small tools

See everything →