npm tokens are actually two distinct types of credentials, and conflating them is the most common way people shoot themselves in the foot.
Let’s see them in action.
First, a read-only token. This token can fetch packages, but it can’t push anything.
# Create a read-only token
npm token create --read-only --description "My CI read token"
# Example output:
# '+' my-ci-read-token xoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxox
This token will be added to your npmrc file, typically in your CI environment.
//npm.pkg.github.com/:_authToken=xoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxox
Now, a publish token. This one can do everything, including pushing new versions of your packages.
# Create a publish token
npm token create --description "My publish token"
# Example output:
# '+' my-publish-token yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
This token is also added to your npmrc, but usually only on your local machine or a dedicated build server.
//registry.npmjs.org/:_authToken=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
The core problem npm tokens solve is granular access control for your packages. Before tokens, you’d often share your primary npm user credentials, which is a massive security risk. Anyone with your username and password could publish anything, or worse, delete your packages. Tokens allow you to grant specific permissions (read-only, read-write) to specific registries (npm’s public registry, your private GitHub Packages registry, etc.) without giving away your master account.
Internally, when you run npm install or npm publish, your local npm client checks your .npmrc file for authentication tokens matching the registry you’re interacting with. If a token is found for the target registry, npm uses that token in the Authorization: Bearer <token> header of its HTTP requests to the registry. The registry then validates the token and, based on its permissions, allows or denies the requested operation.
The key distinction is between publish tokens and read-only tokens. A publish token, by default, has write access. A read-only token explicitly limits its capabilities to fetching packages. You can even create tokens with more fine-grained permissions, like read-only access to specific scoped packages.
The most surprising thing about npm tokens is how easily they can be revoked by the user who created them, and how this revocation is an immediate, global action. If you generate a token and then realize it’s been compromised or is no longer needed, you can log into your npm account on the website, navigate to "Access Tokens," find the token, and click "Revoke." This single action invalidates that specific token across all your projects and CI/CD pipelines instantly. There’s no waiting period, no grace period; the token simply stops working. This immediate revocation is a powerful security feature, but it also means you need to be diligent about managing your tokens and replacing them if they’re revoked unexpectedly.
The next concept you’ll want to understand is how to use these tokens with package managers other than npm, like Yarn or pnpm.