A tarball on the registry proves nothing about where it came from. Provenance fixes that: the CI job that runs npm 2,036 publish also signs a statement naming the repository, commit and workflow that built the tarball, and puts it in Sigstore 69,885 's public transparency log, so anyone can check that the code on GitHub 29 is the code in the package. Trusted publishing removes the token as well — register the workflow as a trusted publisher on the package's settings page, and the runner exchanges a short-lived OIDC identity token for a credential that expires in minutes.

permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with: { node-version: '24', registry-url: 'https://registry.npmjs.org' }
- run: npm ci
- run: npm publishid-token: write is the whole secret: it lets the job request the identity token. npm generates the provenance attestation automatically for a public package built from a public repository on GitHub Actions 29 or GitLab CI/CD 377 ; CircleCI 10,326 is a supported trusted publisher but does not produce provenance. Trusted publishing needs npm 11.5.1 or later on Node 22.14.0 or later, and only cloud runners qualify. Once the publisher is registered, switch the package to "require two-factor authentication and disallow tokens" so a stolen token cannot be used at all, and verify an installed tree with npm audit signatures.