* Add docs for npm auth setup * Show bash examples * Improve bash pattern * Update and reference docs * Remove setup auth code * Update * Update * Update
7.7 KiB
How to set up npm authentication
This is a brief guide on setting up npm authentication in GitHub Actions. Most of the information below are also applicable outside of Changesets and can be referenced for other npm workflows.
Recommended Setup
It is recommended by npm to use Trusted Publishing, or Staged Publishing, or both, to securely publish packages from CI.
Note that Staged Publishing does not work with Changesets at the moment, so it's recommended to use Trusted Publishing instead for now. Check out its docs for more information to set it up.
Also, in contrary to npm's workflow recommendation, make sure the id-token: write is only set on the job that needs to publish. As such, consider splitting the build, test, publish flows etc into separate jobs. Here's an example setup with Changesets:
# .github/workflows/publish.yml
name: Publish
on:
push:
branches:
- main
permissions: {} # recommended: reset permissions
jobs:
select-mode:
runs-on: ubuntu-latest
outputs:
mode: ${{ steps.select-mode.outputs.mode }}
publish-plan-artifact-id: ${{ steps.select-mode.outputs.publish-plan-artifact-id }}
permissions:
contents: read # to check out repo (actions/checkout)
steps:
- uses: actions/checkout@v7
- run: npm install
- uses: changesets/action/select-mode@v2
id: select-mode
version:
if: needs.select-mode.outputs.mode == 'version'
needs: select-mode
runs-on: ubuntu-latest
outputs:
version-dir-artifact-id: ${{ steps.version.outputs.version-dir-artifact-id }}
permissions:
contents: read # to check out repo (actions/checkout)
steps:
- uses: actions/checkout@v7
- run: npm install
- uses: changesets/action/version@v2
id: version
pack:
if: needs.select-mode.outputs.mode == 'publish'
needs: select-mode
runs-on: ubuntu-latest
outputs:
pack-dir-artifact-id: ${{ steps.pack.outputs.pack-dir-artifact-id }}
permissions:
contents: read # to check out repo (actions/checkout)
steps:
- uses: actions/checkout@v7
- run: npm install
- run: npm build
- uses: changesets/action/pack@v2
id: pack
with:
publish-plan-artifact-id: ${{ needs.select-mode.outputs.publish-plan-artifact-id }}
publish:
needs: pack
runs-on: ubuntu-latest
permissions:
id-token: write # for trusted publishing (changesets/action)
steps:
- uses: changesets/action/publish@v2
with:
pack-dir-artifact-id: ${{ needs.pack.outputs.pack-dir-artifact-id }}
Token-based Publishing
Caution
Token-based publishing (with Granular Access Tokens) is no longer recommended, with many restrictions that make it difficult to use in CI workflows. For example:
- They expire after a maximum of 90 days, which requires periodic manual token rotation.
- 2FA-bypass tokens are being deprecated and will soon be not allowed to publish packages with 2FA enabled.
However, if you're using a different npm-compatible registry that does not support Trusted Publishing or Staged Publishing, you may still opt for token-based publishing. Check out the next section for more information.
You'll need an npm token with "Bypass two-factor authentication" checked (to prevent npm requesting 2FA in CI). Add this token as a secret in your GitHub repo with the name NPM_TOKEN so it can be used in the workflow below.
In most cases, you can use actions/setup-node to set up token-based authentication automatically.
# .github/workflows/publish.yml
name: Publish
on:
push:
branches:
- main
permissions: {} # recommended: reset permissions
jobs:
# ... other jobs like select-mode and version
publish:
if: needs.select-mode.outputs.mode == 'publish'
needs: select-mode
runs-on: ubuntu-latest
permissions:
contents: read # to check out repo (actions/checkout)
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
registry-url: https://registry.npmjs.org/ # set this option to set up npm authentication
- run: npm install
- run: npm build
- uses: changesets/action/publish@v2
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # pass the token here
Tip
Pass
registry-url: https://npm.pkg.github.com/andNODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}to publish to the GitHub Package Registry instead of npm.
Internally, actions/setup-node will set up a .npmrc file that looks like this:
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
This syntax allows to authenticate with the npm registry only when the NODE_AUTH_TOKEN environment variable is set, which is the safer approach than storing the token directly in the .npmrc file.
Manual Setup
For advanced use cases, you can also set up the ~/.npmrc file manually. Make sure to remove the registry-url option from actions/setup-node to prevent conflicts with your custom .npmrc file.
For example, if you need to publish different scopes to different registries, you can set up the ~/.npmrc file like below:
- run: |
cat << 'EOF' > ~/.npmrc
# For unscoped packages, publish to the default npm registry
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
# For @foo/* packages, publish to a custom registry
@foo:registry=https://my-registry.com/
//my-registry.com/:_authToken=${NODE_FOO_AUTH_TOKEN}
# For @bar/* packages, publish to the GitHub Package Registry
@bar:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
EOF
Package Managers Edge Cases
pnpm
An .npmrc file in a project directory with pnpm does not support environment variables due to security reasons. As such, it's recommended to set up in the home directory instead. This is also the general recommendation for other package managers to not mix potential existing config setups in projects.
yarn
Yarn does not support the .npmrc file, compared to every other package managers that do. To set up authentication for yarn, use a ~/.yarnrc.yml file instead:
- run: |
cat << 'EOF' > ~/.yarnrc.yml
npmAuthToken: "${NODE_AUTH_TOKEN}"
EOF
For advanced use cases, similar to the .npmrc example above, the equivalent looks something like this:
- run: |
cat << 'EOF' > ~/.yarnrc.yml
npmAuthToken: "${NODE_AUTH_TOKEN}"
npmScopes:
foo:
npmRegistryServer: "https://my-registry.com/"
npmAuthToken: "${NODE_FOO_AUTH_TOKEN}"
bar:
npmRegistryServer: "https://npm.pkg.github.com/"
npmAuthToken: "${GITHUB_TOKEN}"
EOF
Miscellaneous
Other package managers may also support (or recommend) configuring the tokens in their own configuration files. Check their documentation for more information.