---
url: https://relizy.dev/guide/trusted-publishing.md
description: >-
  Publish to npm from GitHub Actions or GitLab CI without npm token - npm trusts
  the CI job through OIDC and adds the provenance of the packages. The setup on
  npmjs.com, in the CI, for a monorepo, and its limits.
---

# {{ $frontmatter.title }}

{{ $frontmatter.description }}

## How It Works

With an npm token, anyone who gets the token can publish your packages, until you revoke it. With trusted publishing, you tell npm once which workflow of which repository may publish a package. At each publish, the CI job gets a short-lived OIDC token from GitHub or GitLab proving which repository and workflow it runs, and npm exchanges it for a publish authorization. There is no secret to store nor to rotate.

npm also adds the **provenance** of the package: its page on npmjs.com links each version to the commit and the run that built it, for a public package published from a public repository.

Relizy needs no option: in a job that can get an OIDC token, without npm token, it publishes to npmjs.org with trusted publishing. With a token too, npm tries OIDC first and falls back to the token.

## Setup

### 1. Publish the First Version

npm cannot create a package with trusted publishing: a new package is published once with an npm token (`NPM_TOKEN`, see [GitHub Actions](./github-actions.md#secrets-and-permissions) or [GitLab CI](./gitlab-ci.md#ci-cd-variables)), or by hand with `npm publish`.

### 2. Add the Trusted Publisher on npmjs.com

On npmjs.com, in the Settings of the package, add a trusted publisher:

* **GitHub Actions**: the owner and the repository, the file name of the workflow (`release.yml`, not its path), and its environment if the job has one.
* **GitLab CI**: the namespace and the project, the top-level pipeline file (`.gitlab-ci.yml`, even when the job is in an included file), and its environment if the job has one.

### 3. Give the Job Its OIDC Token

The workflows generated by `relizy init` already do it.

::: code-group

```yaml [GitHub Actions]
jobs:
  release:
    permissions:
      contents: write
      # npm trusted publishing (OIDC)
      id-token: write
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0
      # Updates npm to 11.5.1 or later, as the job can request an id token
      - uses: relizy/action@v2
```

```yaml [GitLab CI]
# The relizy component requests the NPM_ID_TOKEN id token and updates npm
include:
  - component: gitlab.com/relizy/relizy/release@2
```

```yaml [GitLab CI (job written out)]
release:
  # npm trusted publishing (OIDC)
  id_tokens:
    NPM_ID_TOKEN:
      aud: npm:registry.npmjs.org
  before_script:
    # Trusted publishing needs npm 11.5.1 or later
    - npm install -g npm@latest
    # ... install
  script:
    - pnpm exec relizy release --yes
```

:::

Then remove `NPM_TOKEN` from the secrets, or keep it for the first publish of the next new packages.

## A Monorepo

The trusted publisher is set per package. With npm 11.15 or later, `npm trust` adds it from the command line, for all the packages in one go (npm asks for your two-factor authentication once, and offers to skip it for the next 5 minutes):

```bash
for pkg in @scope/core @scope/utils @scope/vue; do
  npm trust github "$pkg" --repo owner/repo --file release.yml --allow-publish --yes
done
```

On GitLab: `npm trust gitlab "$pkg" --project group/project --file .gitlab-ci.yml --allow-publish --yes`. `npm trust list <package>` shows the trusted publishers of a package. See [npm trust](https://docs.npmjs.com/cli/v11/commands/npm-trust).

A new package of the monorepo still needs its first publish with a token: before the bump, Relizy warns about the packages that are not on npm yet (`Not on npm yet: ...`).

## What Relizy Checks

Before the bump, the [safety check](./../config/publish.md#authentication) of the publication does not run `npm whoami` with trusted publishing (it does not work with OIDC). Instead:

* the npm that publishes must do the OIDC exchange (11.5.1 or later), else the release stops before the bump with the fix. pnpm 10 and earlier publish through npm; pnpm 11 and later publish by themselves.
* the packages that are not on npm yet are listed in a warning: their publish would fail.

Without npm token nor OIDC token in CI, the authentication error tells both ways to publish.

`actions/setup-node` with a `registry-url` and without token fills `NODE_AUTH_TOKEN` with a placeholder (`XXXXX-XXXXX-XXXXX-XXXXX`): Relizy does not take it for a token. You need no `registry-url`.

## Limits

* **npmjs.org only**: another registry (GitHub Packages, a private registry) still needs its token.
* **Hosted runners only**: GitHub-hosted runners and GitLab.com shared runners. npm does not support self-hosted runners yet.
* **No provenance for a private repository**: the package is published, without provenance.
* **Yarn and bun**: Relizy does not check their auth, as without trusted publishing. Check that your version supports OIDC, or publish with a token.

See the [npm documentation](https://docs.npmjs.com/trusted-publishers).
