How trusted publishing works
Instead of copying a publisher key into a CI secret store, you tell the registry which workflow may publish a package. When that workflow runs, the CI provider mints a signed OIDC token describing the run — repository, workflow file, branch, environment. The npm CLI exchanges that token with the registry for a short-lived publisher key, publishes, and discards it. The exchanged key works for about 15 minutes and can only publish that one package. Keep it out of logs too: a short lifetime limits exposure but does not make a leaked credential harmless.
The exchange is the same contract the public npm registry uses, so the stock npm CLI (11.5.1 or newer) drives it with no plugins: it detects GitHub Actions and GitLab CI and handles the token exchange itself.
These instructions target a private package on PrivateNPM.com. If you publish to registry.npmjs.org, use npm's trusted publishing documentation to check that registry's supported providers and configuration rules.
Before you start
- The package must exist. Publish its first version with a publisher key first (see the publishing guide); trusted publishing takes over from the second release.
- npm CLI 11.5.1 or newer and a compatible Node.js version in the workflow. Check
node --versionandnpm --versionin the runner; an older runner image may bundle an older npm CLI. - Credential management permission. Whoever configures the trusted publisher needs
registry:credential:manageand publish rights on the package.
Trust a workflow
- Open Registry → Packages, pick the package, and open Edit.
- Under Trusted publishing, pick the CI provider and enter the repository owner and name and the workflow file that publishes, such as
.github/workflows/publish.ymlor.gitlab-ci.yml. Optionally restrict to one CI environment, or point the issuer at a self-managed GitLab or GitHub Enterprise host. - Save. You become the member exchanged keys act as: every run re-checks that you may still publish, so leaving the organization or losing the grant stops CI publishing.
The same configuration is available to automation as PUT /api/v1/packages/{id}/trusted-publisher in the management API.
Publish from GitHub Actions
The only required change is the id-token: write permission, which lets GitHub mint the OIDC token npm exchanges. Keep the registry mapping in .npmrc as usual — with no token line:
.npmrc:
@acme:registry=https://registry.privatenpm.com/jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # mint the OIDC token npm exchanges
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm publishPublish from GitLab CI
GitLab mints the token as a job variable; the CLI reads NPM_ID_TOKEN. The audience is npm: followed by your registry host:
publish:
image: node:24
id_tokens:
NPM_ID_TOKEN:
aud: npm:registry.privatenpm.com
script:
- npm ci
- npm publishCustom domains and reusable workflows
On a verified custom domain the audience follows the registry host — for npm.acme.com the GitLab audience is npm:npm.acme.com and GitHub Actions derives it from the configured registry URL automatically. The package page shows copy-paste snippets with the right audience filled in. With a GitHub reusable workflow, configure the file that contains the publish step (the called workflow), not the caller stub.
Manage and audit it
Replace or remove the trust on the same edit page; removal takes effect on the next run. Exchanged keys appear under Registry → Keys named after the publisher and expire on their own. Every exchange and every configuration change lands in the organization's audit log, and npm_trusted_publisher.created, npm_trusted_publisher.updated and npm_trusted_publisher.deleted are available as webhook events. Keep a publisher key as a break-glass credential for local releases.
Troubleshoot a trusted publish
- No OIDC token: check the npm version and GitHub's
id-token: writepermission, or the GitLab job'sNPM_ID_TOKENconfiguration. Run the publish step inside the configured CI workflow. - Trust does not match: compare the repository, workflow file and optional environment with the saved configuration. On a custom domain, check that the registry hostname and token audience agree.
- The exchange is denied: confirm that the package exists and that the member who configured the trust still has publishing rights. A renamed repository or changed workflow needs an updated trust.
- Dependency installation fails first: OIDC publishing does not authenticate
npm ci. Give the install step a separate read-only download key using the .npmrc configuration guide. - Authentication succeeds but publishing fails: check for an already-published version and review your plan or trial's publishing requirements. Authentication does not override those checks.
Test the workflow with a new version of a package you control before removing its old CI publisher secret. Never paste tokens or secret-bearing logs into a support request.
Keep the release working
Verify a fresh install of the CI release, then check package download activity as your team starts using it.
Need a workspace for this walkthrough? Start a 30-day trial. No card is required to sign up; add one before publishing.