1 ---
2 title: Trusted publishing for npm packages
3 ---
4
5 Trusted publishing allows you to publish npm packages directly from your CI/CD workflows using [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) authentication, eliminating the need for long-lived npm tokens. This feature implements the [trusted publishers industry standard](https://repos.openssf.org/trusted-publishers-for-all-package-repositories) specified by the Open Source Security Foundation (OpenSSF), joining a growing ecosystem including [PyPI](https://docs.pypi.org/trusted-publishers/), [RubyGems](https://guides.rubygems.org/trusted-publishing/), and other major package registries in offering this security enhancement.
6
7 <Note>
8
9 **Note:** Trusted publishing requires [npm CLI](https://docs.npmjs.com/cli/v11) version 11.5.1 or later and Node version 22.14.0 or higher.
10
11 </Note>
12
13 ## How trusted publishing works
14
15 Trusted publishing creates a trust relationship between npm and your CI/CD provider using OIDC. When you configure a trusted publisher for your package, npm will accept publishes from the specific workflow you've authorized, in addition to traditional authentication methods like npm tokens and manual publishes. The npm CLI automatically detects OIDC environments and uses them for authentication before falling back to traditional tokens.
16
17 This approach eliminates the security risks associated with long-lived write tokens, which can be compromised, accidentally exposed in logs, or require manual rotation. Instead, each publish uses short-lived, cryptographically-signed tokens that are specific to your workflow and cannot be extracted or reused.
18
19 ## Supported CI/CD providers
20
21 Trusted publishing currently supports:
22
23 - [GitHub Actions](https://github.com/features/actions) (GitHub-hosted runners)
24 - [GitLab CI/CD Pipelines](https://docs.gitlab.com/ci/pipelines/) (GitLab.com shared runners)
25 - [CircleCI](https://circleci.com/) (CircleCI cloud)
26
27 Self-hosted runners are not currently supported but are planned for future releases.
28
29 ## Configuring trusted publishing
30
31 ### Step 1: Add a trusted publisher on npmjs.com
32
33 Navigate to your package settings on [npmjs.com](https://www.npmjs.com) and find the "**Trusted Publisher**" section. Under "**Select your publisher**", choose your CI/CD provider by clicking the GitHub Actions, GitLab CI/CD, or CircleCI button.
34
35 <Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher.png" alt="Screenshot showing the Trusted Publisher section with Select your publisher label and provider buttons" />
36
37 #### For GitHub Actions
38
39 Configure the following fields:
40
41 - **Organization or user** (required): Your GitHub username or organization name
42 - **Repository** (required): Your repository name
43 - **Workflow filename** (required): The filename of your workflow (e.g., `publish.yml`)
44 - Enter only the filename, not the full path
45 - Must include the `.yml` or `.yaml` extension
46 - The workflow file must exist in `.github/workflows/` in your repository
47 - **Environment name** (optional): If using [GitHub environments](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) for deployment protection
48 - **Allowed actions** (required): Select which actions this trusted publisher can perform — `npm publish`, `npm stage publish`, or both. At least one must be selected. See [Staged publishing for npm packages](/staged-publishing) for more information on staged publishing.
49
50 <Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher-github-actions.png" alt="Screenshot of GitHub Actions trusted publisher configuration form" />
51
52 #### For GitLab CI/CD
53
54 Configure the following fields:
55
56 - **Namespace** (required): Your GitLab username or group name
57 - **Project name** (required): Your project name
58 - **Top-level CI file path** (required): The path to your CI file (e.g., `.gitlab-ci.yml`)
59 - Must include the `.yml` extension
60 - **Environment name** (optional): If using [GitLab environments](https://docs.gitlab.com/ee/ci/environments/)
61 - **Allowed actions** (required): Select which actions this trusted publisher can perform — `npm publish`, `npm stage publish`, or both. At least one must be selected.
62
63 <Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher-gitlab.png" alt="Screenshot of GitLab CI/CD trusted publisher configuration form" />
64
65 #### For CircleCI
66
67 Configure the following fields:
68
69 - **Organization ID** (required): Your CircleCI organization ID (UUID format). You may find it from your CircleCI Organization Settings Overview page.
70 - **Project ID** (required): Your CircleCI project ID (UUID format). You may find it from your CircleCI Project Settings Overview page.
71 - **Pipeline definition ID** (required): The pipeline definition ID (UUID format). You may find it from your CircleCI Project Settings under Project Setup page.
72 - **VCS origin** (required): The VCS origin URL for your project (e.g., `github.com/myorg/myrepo`)
73 - **Context IDs** (optional): Restrict publishing to jobs using specific CircleCI contexts. You may find them from your CircleCI Organization Settings Contexts.
74 - **Allowed actions** (required): Select which actions this trusted publisher can perform — `npm publish`, `npm stage publish`, or both. At least one must be selected.
75
76 For more in-depth information see [CircleCI's guide](https://circleci.com/docs/guides/deploy/deploy-to-npm-registry/).
77
78 <Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher-circleci.png" alt="Screenshot of CircleCI trusted publisher configuration form" />
79
80 <Note>
81
82 **Note:** Each package can only have one trusted publisher configured at a time.
83
84 </Note>
85
86 <Note>
87
88 **Note:** Trusted publisher configurations created before May 20, 2026 are automatically set to allow `npm publish` only — no behavior change occurs for current workflows. Configurations created after May 20, 2026 require you to explicitly select at least one allowed action.
89
90 </Note>
91
92 ### Step 2: Configure your CI/CD workflow
93
94 #### GitHub Actions configuration
95
96 Add the required OIDC permissions to your workflow. Here's a complete example:
97
98 ```yaml
99 name: Publish Package
100
101 on:
102 push:
103 tags:
104 - 'v*'
105
106 permissions:
107 id-token: write # Required for OIDC
108 contents: read
109
110 jobs:
111 publish:
112 runs-on: ubuntu-latest
113 steps:
114 - uses: actions/checkout@v6
115
116 - uses: actions/setup-node@v6
117 with:
118 node-version: '24'
119 registry-url: 'https://registry.npmjs.org'
120 package-manager-cache: false # never use caching in release builds
121 - run: npm ci
122 - run: npm run build --if-present
123 - run: npm test
124 - run: npm publish # Or: npm stage publish
125 ```
126
127 The critical requirement is the `id-token: write` permission, which allows GitHub Actions to generate OIDC tokens. Learn more in [GitHub's OIDC documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect).
128
129 #### GitLab CI/CD configuration
130
131 Configure the OIDC ID token in your pipeline:
132
133 ```yaml
134 stages:
135 - test
136 - build
137 - publish
138
139 variables:
140 NODE_VERSION: '24'
141
142 test:
143 stage: test
144 image: node:${NODE_VERSION}
145 script:
146 - npm ci
147 - npm test
148
149 publish:
150 stage: publish
151 image: node:${NODE_VERSION}
152 id_tokens:
153 NPM_ID_TOKEN:
154 aud: "npm:registry.npmjs.org"
155 SIGSTORE_ID_TOKEN:
156 aud: sigstore
157 script:
158 - npm ci
159 - npm run build --if-present
160 - npm publish # Or: npm stage publish
161 only:
162 - tags
163 ```
164
165 The `id_tokens` configuration tells GitLab to generate an OIDC token for npm. Learn more in [GitLab's OIDC documentation](https://docs.gitlab.com/ee/ci/cloud_services/).
166
167 <Note>
168
169 **Note:** Don't forget to configure id_tokens 'aud' to `"npm:registry.npmjs.org"` in your GitLab pipeline.
170
171 </Note>
172
173 #### CircleCI configuration
174
175 Set the `NPM_ID_TOKEN` environment variable with an OIDC token from CircleCI, and npm CLI handles the token exchange automatically. Here's a complete example:
176
177 ```yaml
178 version: 2.1
179
180 jobs:
181 publish:
182 docker:
183 - image: cimg/node:22.14
184 steps:
185 - checkout
186 - run:
187 name: Install dependencies
188 command: npm ci
189 - run:
190 name: Run tests
191 command: npm test
192 - run:
193 name: Build
194 command: npm run build --if-present
195 - run:
196 name: Publish to npm with OIDC
197 command: |
198 export NPM_ID_TOKEN=$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}')
199 npm publish # Or: npm stage publish
200
201 workflows:
202 publish:
203 jobs:
204 - publish:
205 filters:
206 tags:
207 only: /^v.*/
208 branches:
209 ignore: /.*/
210 ```
211
212 The `circleci run oidc get` command retrieves an OIDC token from CircleCI. When `NPM_ID_TOKEN` is set, the npm CLI automatically exchanges it for a short-lived publish token. Learn more in [CircleCI's OIDC documentation](https://circleci.com/docs/openid-connect-tokens/).
213
214 ### Managing trusted publisher configurations
215
216 You can modify or remove your trusted publisher configuration at any time through your package settings on [npmjs.com](https://npmjs.com) → Packages → YOUR_PACKAGE → Settings → Trusted publishing. Each package can only have one trusted publisher connection at a time, but this connection can be edited or deleted as needed. To change providers (for example, switching from GitHub Actions to GitLab CI/CD), simply edit your existing configuration and select the new provider. The change takes effect immediately for future publishes. To remove trusted publishing entirely and return to token-based authentication, delete the trusted publisher configuration from your package settings.
217
218 ## Recommended: Restrict token access when using trusted publishers
219
220 Once you've configured trusted publishers for your package, we strongly recommend restricting traditional token-based publishing access for enhanced security.
221
222 ### How to configure maximum security
223
224 1. After enabling trusted publishers, navigate to your package's **Settings** → **Publishing access**
225 2. Select **"Require two-factor authentication and disallow tokens"**
226 3. Save your changes by clicking on **Update Package Settings**
227
228 ### Why this matters
229
230 Trusted publishers use short-lived, scoped credentials that are generated on-demand during your CI/CD workflow, eliminating the need for long-lived tokens. By restricting traditional token access while using trusted publishers, you reduce potential security risks associated with credential management.
231
232 For even stronger security, configure your trusted publisher with **stage-only permissions** (allow `npm stage publish` but not `npm publish`). This ensures all CI-automated publishes go through the [staged publishing](/staged-publishing) flow, requiring a maintainer to review and approve each package with 2FA via the CLI or [npmjs.com](https://www.npmjs.com) before it becomes publicly available. Combined with disallowing tokens, this provides the maximum security posture for your packages.
233
234 **Note:** The "disallow tokens" setting only affects traditional token authentication. Your trusted publishers will continue to work normally, as they use OIDC tokens.
235
236 ### Migration tip
237
238 If you're transitioning from token-based publishing:
239
240 1. Set up trusted publishers first and verify they work
241 2. Then restrict token access as described above
242 3. [Revoke any existing automation tokens](https://docs.npmjs.com/revoking-access-tokens) that are no longer needed
243
244 This ensures a smooth transition without disrupting your release process.
245
246 ## Automatic provenance generation
247
248 When you publish using trusted publishing from GitHub Actions or GitLab CI/CD, npm automatically generates and publishes [provenance attestations](./generating-provenance-statements) for your package. This happens by default—you don't need to add the `--provenance` flag to your publish command.
249
250 <Note>
251
252 **Note:** Provenance generation is not currently supported for CircleCI. Packages published via CircleCI trusted publishing will not include provenance attestations.
253
254 </Note>
255
256 <Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher-provenance.png" alt="Screenshot showing provenance badge/information on a package page" />
257
258 Provenance provides cryptographic proof of where and how your package was built, allowing users to verify its authenticity. This automatic generation only applies when all of these conditions are met:
259
260 - Publishing via trusted publishing (OIDC)
261 - Publishing from a public repository
262 - Publishing a public package
263
264 <Note>
265
266 **Note:** Provenance generation is [not supported for private repositories](https://github.blog/changelog/2023-07-25-publishing-with-npm-provenance-from-private-source-repositories-is-no-longer-supported/), even when publishing public packages.
267
268 </Note>
269
270 ### Disabling provenance generation
271
272 While we strongly recommend keeping provenance enabled, you can disable it if needed. Set the `provenance` option to `false` in any of these ways:
273
274 **Using environment variable:**
275
276 ```bash
277 NPM_CONFIG_PROVENANCE=false npm publish
278 ```
279
280 **In your `.npmrc` file:**
281
282 ```ini
283 provenance=false
284 ```
285
286 **In your `package.json`:**
287
288 ```json
289 {
290 "publishConfig": {
291 "provenance": false
292 }
293 }
294 ```
295
296 ## Security best practices
297
298 ### Prefer trusted publishing over tokens
299
300 When trusted publishing is available for your workflow, always prefer it over long-lived tokens. Traditional npm tokens pose several security risks:
301
302 - They can be accidentally exposed in CI logs or configuration files
303 - They require manual rotation and management
304 - If compromised, they provide persistent access until revoked
305 - They often have broader permissions than necessary
306
307 Trusted publishing eliminates these risks by using short-lived, workflow-specific credentials that are automatically managed and cannot be extracted.
308
309 ### Handling private dependencies
310
311 While trusted publishing handles the publish operation, you may still need authentication for installing private npm dependencies. For this scenario, we recommend:
312
313 ```yaml
314 # GitHub Actions example
315 - uses: actions/setup-node@v6
316 with:
317 node-version: '24'
318 registry-url: 'https://registry.npmjs.org'
319 package-manager-cache: false # never use caching in release builds
320 # Use a read-only token for installing dependencies
321 - run: npm ci
322 env:
323 NODE_AUTH_TOKEN: ${{ secrets.NPM_READ_TOKEN }}
324
325 # Publish uses OIDC - no token needed
326 - run: npm publish
327 ```
328
329 Always use [read-only granular access tokens](/creating-and-viewing-access-tokens#creating-granular-access-tokens-on-the-website) for installing dependencies. This limits potential damage if the token is ever compromised.
330
331 ### Additional security measures
332
333 Consider implementing these additional security practices:
334
335 - Use [deployment environments](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) to add approval requirements
336 - Enable [tag protection rules](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/configuring-tag-protection-rules) to control who can create release tags
337 - Regularly audit your trusted publisher configurations
338 - Remove any unused publish tokens from your npm account
339
340 ## Troubleshooting
341
342 If you encounter an "Unable to authenticate" (ENEEDAUTH) error when publishing, first verify that the workflow filename matches exactly what you configured on [npmjs.com](https://npmjs.com), including the `.yml` extension. All fields are case-sensitive and must be exact. Also ensure you're using GitHub-hosted runners, GitLab.com shared runners, or CircleCI cloud, as self-hosted runners are not currently supported. For GitHub Actions specifically, check that the `id-token: write` permission is set in your workflow. For CircleCI, verify that your Organization ID, Project ID, and Pipeline definition ID match your CircleCI configuration.
343
344 <Note>
345
346 **Note:** npm does not verify your trusted publisher configuration when you save it. Double-check that your repository, workflow filename, and other details are correct, as errors will only appear when you attempt to publish.
347
348 </Note>
349
350 To publish from GitHub, your package's `repository.url` field in `package.json` must exactly match your GitHub repository. This may be an issue for misconfigured packages, but could also impact publication from forks that haven't updated `package.json` to match the forked repo.
351
352 If your package has private dependencies and `npm install` or `npm ci` is failing with authentication errors, remember that trusted publishing only applies to the `npm publish` command. You'll still need to provide a read-only token for installing private packages as shown in the examples above.
353
354 For packages in private repositories, provenance will not be generated even though you're using trusted publishing. This is a [known limitation](https://github.blog/changelog/2023-07-25-publishing-with-npm-provenance-from-private-source-repositories-is-no-longer-supported/) that applies regardless of whether your package itself is public or private.
355
356 Some GitHub Actions workflows use `workflow_call` to invoke other workflows that run `npm publish`, or use `workflow_dispatch` for manual publishing. When this happens, validation checks the calling workflow's name instead of the workflow that actually contains the publish command, which can cause configuration mismatches. The `id-token: write` permission must also be given to both parent and child workflows.
357
358 ## Limitations and future improvements
359
360 Trusted publishing currently supports only cloud-hosted runners. Support for self-hosted runners is intended for a future release. Each package can only have one trusted publisher configured at a time, though you can update this configuration as needed.
361
362 OIDC authentication supports the `npm publish` and `npm stage publish` commands. Other stage subcommands (`npm stage list`, `npm stage view`, `npm stage approve`, `npm stage reject`) require interactive authentication and cannot use OIDC tokens, as these actions require proof of presence and can only be performed via the CLI or [npmjs.com](https://www.npmjs.com). Other npm commands such as `install`, `view`, or `access` still require traditional authentication methods. The `npm whoami` command will not reflect OIDC authentication status since the authentication occurs only during the publish or stage operation.
363
364 We intend to expand trusted publishing support to additional CI/CD providers and enhance the feature based on community feedback.
365
366 ## Learn more
367
368 - [Staged publishing for npm packages](./staged-publishing)
369 - [About npm provenance](./generating-provenance-statements)
370 - [OpenSSF Trusted Publishers specification](https://repos.openssf.org/trusted-publishers-for-all-package-repositories)
371 - [GitHub Actions OIDC documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
372 - [GitLab CI/CD OIDC documentation](https://docs.gitlab.com/ee/ci/cloud_services/)
373 - [CircleCI OIDC documentation](https://circleci.com/docs/openid-connect-tokens/)
374 - [CircleCI guide to setting up npm trusted publishing](https://circleci.com/docs/guides/deploy/deploy-to-npm-registry/)
375 - [API documentation for exchanging OIDC ID token for npm registry token](https://api-docs.npmjs.com/#tag/registry.npmjs.org/operation/exchangeOidcToken)