Publish npm Packages Without Tokens
Publish an npm package from GitHub Actions with trusted publishing.
Introduction
30 Second Summary
A saved login key can sit forgotten in a project's settings for years. Every forgotten key leaves one more door that somebody has to guard.
In this project, you will publish a small package to the public npm registry through a GitHub Actions workflow that uses trusted publishing. You will follow its provenance badge back to the commit that built the release.
What You'll Build
Picture your package page showing a new workflow-published version with a provenance badge that traces back to its source commit.
By the end of this project, you'll have:
- A real public package that performs its job locally before appearing on npm.
- A token-free release you trigger by tagging a new version in GitHub.
- A provenance badge that points from the published version to its exact build record.
- Secret Mission: Add a second trusted publishing configuration for a separate GitHub Actions release workflow.
What do I need before I start?
You need an npm account with 2FA enabled. You also need a GitHub account with Node installed on your computer.
Public package publishing plus workflow minutes for public repositories cost nothing for this project.
Before We Start
Trusted publishing lets a release workflow prove its identity without a long-lived token. That secure release still depends on local tools plus online accounts being ready first.
In this step, you'll prepare Node.js, npm, Git, a terminal, plus a code editor. You'll also confirm browser access to GitHub and the npm registry.
In this step, get ready to:
- Install an LTS release of Node.js with npm.
- Prepare Git, a terminal, and a code editor.
- Create or access GitHub and npm accounts in your browser.
Install Node.js and npm
Node.js runs JavaScript outside a browser. Its LTS installer includes npm, which manages package files plus publishing commands.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal on macOS or PowerShell on Windows. Press Enter.
- Check your Node.js and npm versions by running:
node --version
npm --version
What do these checks prove?
- node --version confirms that the Node.js runtime is available in your terminal.
- npm --version confirms that the bundled package manager is available.
The official download page currently lists v24.20.0 as the latest LTS release. It also lists v22.23.2 as an LTS release.
✔️ Both commands show LTS versions
Both commands should print version numbers. A Node.js result beginning with v24. or v22. belongs to an LTS release listed by Node.js.
ⓧ Node.js is not an LTS release
Your terminal can find Node.js, but the installed release does not match a listed LTS line. Install the current LTS release before continuing.
- Visit the official Node.js download page.
- Select the release marked LTS.
- Download the installer for your operating system.
- Run the installer with its default components.
- Start a fresh terminal session through your operating system search.
- Rerun the two version checks above.
ⓧ Command not found
The command is unavailable because Node.js is missing from your system path. The official LTS installer adds Node.js plus npm.
- Visit the official Node.js download page.
- Select the release marked LTS.
- Download the installer for your operating system.
- Run the installer with its default components.
- Start a fresh terminal session through your operating system search.
- Rerun the two version checks above.
Your package toolchain now responds in the terminal.
Still Missing a Version?
Start a fresh terminal session after installing Node.js. An older terminal session may still use the previous system path.
Ask for help: Help me fix my Node.js or npm version check.
Prepare Git and your editor
Git records each package change before GitHub receives it. A code editor gives you a clear place to create the package files in the next step.
- Switch back to the terminal from the Node.js check.
- Check whether Git is installed by running:
git --version
What Does This Check Prove?
The command prints the installed Git version when Git is available through your system path. Any recent Git release is suitable for this project.
✔️ I see a Git version
Git is ready to track your package files.
ⓧ Command not found
Install Git through the official instructions for your operating system.
- Visit the official Git installation page.
- Select your operating system.
- Download the recommended installer.
- Run the installer with its default options.
- Start a fresh terminal session through your operating system search.
- Rerun the Git version check above.
Git Still Unavailable?
Close every terminal window after the installation. A fresh session reloads the system path that points to Git.
Ask for help: Help me make Git available in my terminal.
This project uses Visual Studio Code as its code editor. The editor provides a file sidebar plus an editing area for the package files.
- Press Cmd+Space (macOS) or the Windows key (Windows) to return to your search bar.
- Type Visual Studio Code. Press Enter.
✔️ The editor opens
You should see an editor window with a file sidebar plus an editing area. Visual Studio Code is ready for the package files.
ⓧ I need a code editor
Install Visual Studio Code before continuing.
- Visit the official Visual Studio Code download page.
- Download the installer for your operating system.
- Run the installer with its default options.
- Return to your operating system search bar.
- Type Visual Studio Code. Press Enter.
Your local workspace is ready for package development.
Set up your publishing accounts
GitHub hosts the public repository that triggers your release workflow. Your npm account owns the package that the workflow publishes.
Your route depends on whether these accounts already exist. Choose the tab that matches your current situation.
✔️ I have both accounts
- Visit GitHub in your browser.
- Complete the sign-in form if GitHub asks for your credentials.
- Visit npm in another browser tab.
- Complete the sign-in form if npm asks for your credentials.
ⓧ I need one or both accounts
Create only the account that you do not already have. Both services require a verified email for the work ahead.
- Visit the official GitHub signup page.
- Complete the GitHub signup prompts.
- Verify your email using the message GitHub sends.
- Visit the official npm signup page.
- Complete the npm signup form.
- Agree to the End User License Agreement plus Privacy Policy.
- Click Create An Account.
- Verify your email using the message npm sends.
Both services can now recognize you in the browser.
Two-factor authentication protects your npm account with a second sign-in check. npm requires 2FA or a bypass-enabled token for a manual package publish.
Account security can feel high stakes. These steps only add a second authentication method to your npm account.
The security controls take a few clicks to reach, so this part can feel fiddly.
- Return to the npm browser tab from earlier.
- Click your profile picture.
- Click Account.
- Find Two-Factor Authentication.
- Click Enable 2FA.
- Enter your current npm account password.
- Select your preferred authentication method.
- Click Continue.
- Complete the browser prompts for your chosen authentication method.
- Store any recovery codes in a private password manager.
Keep Recovery Codes Private
Recovery codes can restore access to your npm account. Keep them out of screenshots, repositories, project files, plus chat messages.
Before you refresh both account pages, do you expect each service to recognize the browser session you just prepared?
- Return to the GitHub browser tab from earlier.
- Refresh the GitHub page.
- Confirm that your profile controls are visible.
- Return to the npm browser tab from earlier.
- Refresh the npm account page.
- Confirm that the page shows two-factor authentication as enabled.
You should remain signed in to both services. Your npm account should now have two-factor authentication enabled.
Your local tools plus publishing accounts are ready. Next, you'll create a small package locally and watch it do its first job in the terminal.
Create and Test Your Package
A package release needs a local proof before anyone can install it. A successful local run gives later publishing steps a known working starting point.
In this step, you'll create a scoped npm package at version 1.0.0. Its test script will print a success message in your terminal.
In this step, get ready to:
- Create a local package manifest in a dedicated folder.
- Add an executable JavaScript entry point.
- Prove the package works through its npm test script.
Create the package manifest
The package.json file is your package manifest. It records the package identity plus the files npm should use.
- Record the npm username for your existing account here: <your-npm-username>.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create the trusted-publish-demo folder by running this command:
mkdir trusted-publish-demo
- Confirm the new folder exists by running:
ls
You should see trusted-publish-demo in the output.
- Move into the new folder by running this command:
cd trusted-publish-demo
- Use your code editor's folder controls to load ~/Desktop/trusted-publish-demo.
You should see the empty trusted-publish-demo folder in your editor.
- Create package.json inside the trusted-publish-demo folder with this content:
{
"name": "@[[NPM_USERNAME="<your-npm-username>"]]/trusted-publish-demo",
"version": "1.0.0",
"main": "index.js",
"bin": {
"trusted-publish-demo": "index.js"
},
"scripts": {
"test": "node index.js"
},
"publishConfig": {
"access": "public"
}
}
What does this manifest configure?
- The name field places the package under your npm username.
- The version field starts the package at 1.0.0.
- The main field makes index.js the package entry point.
- The bin field maps the trusted-publish-demo command to index.js.
- The publishConfig field sets the package's publishing access to public.
- Save package.json.
- Confirm the manifest exists by running:
ls
You should see package.json in the output.
Can't find the manifest?
Check that your editor saved the file at ~/Desktop/trusted-publish-demo/package.json. A file saved outside that folder does not appear in this terminal listing.
Ask for help: Help me find where my package.json file was saved.
Add the executable program
The manifest points both the package entry point and its executable command at index.js. This file performs one visible job so you can verify the package locally.
- Create index.js inside the trusted-publish-demo folder with this content:
#!/usr/bin/env node
// Keep the package's single job in one small function.
function printSuccessMessage() {
const message = "Trusted publish demo works.";
console.log(message);
}
// Run the function whenever the package executes.
printSuccessMessage();
What does this program do?
- The first line tells the installed command to execute with Node.js.
- The printSuccessMessage() function keeps the package's single job in one place.
- The message variable holds the text that proves the program ran.
- The final function call prints that text whenever the package executes.
- Save index.js.
- Confirm both package files exist by running:
ls
You should see index.js plus package.json in the output.
Missing the entry point?
Make sure the filename is exactly index.js. Check that your editor did not add a text-file extension.
Ask for help: Help me check why index.js is missing from my package folder.
✔️ Awesome, I've got everything!
Great. Double check that both files are saved before testing the package.
ⓧ I'd like to double check the full code
Compare these complete files with the versions in your trusted-publish-demo folder.
{
"name": "@[[NPM_USERNAME="<your-npm-username>"]]/trusted-publish-demo",
"version": "1.0.0",
"main": "index.js",
"bin": {
"trusted-publish-demo": "index.js"
},
"scripts": {
"test": "node index.js"
},
"publishConfig": {
"access": "public"
}
}
#!/usr/bin/env node
// Keep the package's single job in one small function.
function printSuccessMessage() {
const message = "Trusted publish demo works.";
console.log(message);
}
// Run the function whenever the package executes.
printSuccessMessage();
Run the package locally
The test script connects npm to the program defined in index.js. This final run checks that the manifest points to a working entry point.
Before you run the test, what message do you expect the package to print?
- Run the package through its npm test script with this command:
npm test
What should I see?
npm reads the test entry from package.json. That entry launches index.js with Node.js.
You should see Trusted publish demo works. beneath npm's test-script details. The script heading should also show version 1.0.0.
Test not printing the message?
- Check every comma plus quotation mark in package.json if npm reports that it cannot read the manifest.
- Confirm the test script points to node index.js.
- Confirm index.js contains the final printSuccessMessage() call.
Ask for help: Help me debug why npm test does not print my success message.
That first local success gives you a release candidate you can trust. Next, you'll put these exact files in a public GitHub repository.
Push the Package to GitHub
Your package already runs successfully on your computer. Now it needs a public home that GitHub Actions can access in a later step.
Git records an exact snapshot of your package files. GitHub stores that snapshot online so you can verify what future publishing workflows receive.
In this step, get ready to:
- Commit package.json and index.js to local Git history.
- Create a public GitHub repository without starter files.
- Push the main branch to GitHub.
Capture a local checkpoint
A commit captures the package at a specific point in time. Staging only the two package files keeps this first snapshot focused.
- Switch back to the terminal that is already in your local trusted-publish-demo folder.
- Initialize the package as a Git repository by running:
git init -b main
git status
What did Git set up?
- The first command creates the hidden repository metadata inside trusted-publish-demo.
- The -b flag starts the repository on the main branch.
- The second command reports the current state of your local repository.
You should see Git report an empty repository on the main branch.
Git could not initialize the folder?
- Confirm your terminal is inside the trusted-publish-demo folder.
- Check that the folder contains package.json and index.js.
Ask for help: Help me initialize Git in my trusted-publish-demo folder.
- Stage only the package files by running:
git add package.json index.js
git status
What did staging prove?
- The first command selects package.json and index.js for the commit.
- The status check lets you inspect the staged file list before creating permanent history.
You should see package.json and index.js listed as staged files. No other project file should appear in that staged list.
Missing a staged file?
- Confirm both filenames match the names in your code editor.
- Check that both files sit directly inside the trusted-publish-demo folder.
Ask for help: Help me find why one of my package files is missing from Git staging.
- Create the first commit by running:
git commit -m "First commit"
git status
What did the commit capture?
- The commit stores a snapshot containing the version 1.0.0 package manifest.
- The same snapshot stores the executable index.js entry point.
- The status check confirms that no staged changes remain.
You should see a successful commit summary followed by a clean state. That is your first durable checkpoint for the package.
Commit blocked by your Git identity?
Git may ask you to configure an author name or email before it creates the commit. Follow the guidance shown in your terminal before retrying the commit.
Ask for help: Help me resolve the Git identity request blocking my first commit.
Prepare the public repository
GitHub needs an empty repository that can receive your existing commit. Leaving the starter options unselected avoids introducing a separate history before your first push.
- Open the new repository page in the GitHub browser session from earlier.
- Select <your-github-username> from the Owner dropdown.
- Enter trusted-publish-demo in the Repository name field.
- Select Public as the repository visibility.
- Leave every optional initialization choice unselected.
- Click Create repository.
You should reach the Quick Setup page for your empty public repository. Your GitHub destination is ready to receive the package.
Complete the repository handoff
A Git remote connects your local history to an online repository. The conventional remote name origin gives your push command a short name for that destination.
- Connect the local repository to its GitHub destination by running:
git remote add origin https://github.com/[[YOUR_GITHUB_USERNAME="<your-github-username>"]]/trusted-publish-demo.git
git remote -v
What does the remote do?
- The first command associates origin with your public GitHub repository.
- The second command prints the saved address so you can verify the destination.
You should see the same GitHub repository address for incoming operations and outgoing operations.
Does origin already exist?
- Compare the existing origin address with the repository address printed above.
- Use GitHub's remote-management guide to replace an incorrect address.
Ask for help: Help me correct the origin remote for this repository.
Before you push, do you expect the empty GitHub repository to gain the committed files? Make your prediction now.
- Push the local main branch by running:
git push -u origin main
What did the push do?
- The push uploads your first commit to the remote named origin.
- The -u flag stores the relationship between your local main branch and its remote counterpart.
- Future pushes can reuse that saved relationship.
You should see the push finish with your local main branch connected to the remote main branch.
Push blocked by authentication?
- Complete the browser sign-in if Git Credential Manager opens one.
- Complete two-factor authentication if GitHub requests it.
- Use a credential helper or personal access token if the terminal requests a password.
- Avoid entering your GitHub account password because password-based Git authentication is unsupported.
Ask for help: Help me diagnose why my Git push to GitHub was rejected. You can also search GitHub Community discussions.
Before you refresh, which files do you expect the repository page to show? Picture the file list first.
- Return to the GitHub repository page from earlier.
- Refresh the browser page.
You should see a Public repository named <your-github-username>/trusted-publish-demo. The file list should contain package.json and index.js.
- Select package.json from the repository file list.
You should see your scoped package name. You should also see version 1.0.0.
- Use your browser's back button to return to the repository file list.
- Select index.js from the repository file list.
You should see the executable JavaScript that prints the same success message you tested locally.
- Use your browser's back button to return to the repository file list.
Your tested package now has a public GitHub history containing exactly the files you expect. Next, you'll publish version 1.0.0 to npm for the first time.
Publish the First Version
Your public GitHub repository now holds the tested package. The package still exists only as source code in that repository.
Trusted publishing needs an existing package record in the npm registry. In this step, you will create that record with a manual release of 1.0.0.
In this step, get ready to:
- Authenticate the npm CLI through the browser.
- Publish the scoped package as a public package.
- Open the npm package page to confirm version 1.0.0 is available.
Authenticate the npm CLI
The npm CLI needs a local authenticated session before it can publish under your account. The browser flow keeps your password away from your project files.
Your package name is @<your-npm-username>/trusted-publish-demo. Its scope must match your npm username.
- Switch back to the terminal in your local trusted-publish-demo folder from earlier.
- Authenticate the npm CLI by running this command:
npm login
What does this command do?
The npm login command starts an interactive sign-in for the npm registry. The default web flow gives you a browser authentication page.
Successful authentication lets the CLI publish packages owned by your account. It does not add a secret to your GitHub repository.
- Press Enter when the terminal prompts you to open the browser.
- Complete the npm authentication flow in your browser.
- Approve the configured two-factor authentication check.
- Return to the terminal after the browser confirms authentication.
The terminal should confirm that your npm account is authenticated.
Before you check, which npm username do you expect the CLI to return?
- Verify the authenticated username by running this command:
npm whoami
What does this command prove?
The npm whoami command asks the registry which account owns the current authenticated session. The returned username must match the scope in your package name.
You should see your npm username in the terminal. Good progress. The CLI can now publish under your account.
Browser login not completing?
- Use the authentication URL shown in the terminal to load the page manually.
- Complete your account security setup with npm's 2FA setup guide if npm requires it.
Ask for help: Why is my npm browser login not completing?
Publish version 1.0.0
The first release creates the package record that the trusted publisher configuration needs later. Scoped packages require the public access flag on their initial public release.
This action makes the package contents public. npm may ask you to approve the release with your configured 2FA method.
- Publish the scoped package publicly by running this command:
npm publish --access public
What does this command publish?
- The npm publish command reads package.json. It uploads the package files to the npm registry.
- The --access public flag gives the initial scoped release public visibility.
- The published identity comes from your local npm session. No GitHub Actions secret is involved.
- Complete the 2FA approval if npm requests it.
The terminal should report your package name with version 1.0.0 as published. That is the bootstrap release done. Your package now exists in the public registry.
Publish command rejected?
- Check that the scope in package.json matches the username returned by npm whoami.
- Confirm that 2FA is enabled for your npm account.
- Check your package page before retrying if npm says the version already exists.
Ask for help: Why did npm reject my first public package release?
Verify the public package page
The registry response proves that npm can retrieve the exact published version. The package page gives you visible confirmation that the release is public.
Before you check, which version should the npm registry return?
- Query the published version by running this command:
npm view [[PACKAGE_NAME="@<your-npm-username>/trusted-publish-demo"]]@1.0.0 version
What does this check prove?
The npm view command reads package metadata from the registry. Specifying version 1.0.0 confirms that the exact release is publicly retrievable.
You should see 1.0.0 in the terminal. The registry can now find your published release.
- Paste this package URL into your browser address bar:
https://npmjs.com/package/[[PACKAGE_NAME="@<your-npm-username>/trusted-publish-demo"]]
What does this URL open?
This URL points to the npm registry page for your exact package scope. The page shows the package's public metadata with its available version.
- Press Enter to load the package page.
- Check the package header to confirm its visibility.
You should see your package name with public beneath it. You should also see version 1.0.0 on the page.
Package page missing?
- Compare the package name in the page URL with the name value in package.json.
- Wait briefly before checking the page again if the publish command just completed.
Ask for help: Why can I retrieve my npm version in the terminal but not see the package page?
Your public package record is ready. Next, you will connect that package to a named workflow so future releases can publish without a token stored in GitHub.
Configure Trusted Publishing
Your first package version is live on npm. Releasing the next version through automation needs a secure way for the workflow to prove its identity.
Trusted publishing lets one GitHub Actions workflow authenticate through OpenID Connect (OIDC) instead of a stored token. You will commit that workflow before authorizing its exact identity on npm.
In this step, get ready to:
- Create a tag-triggered GitHub Actions publish workflow.
- Commit the workflow to your public repository.
- Authorize the repository and workflow through npm trusted publishing.
Create the publish workflow
A GitHub Actions workflow is a YAML file stored under .github/workflows/. This workflow listens for version tags before publishing the tagged commit.
- Return to the trusted-publish-demo project in your code editor from earlier.
- Create a .github folder inside trusted-publish-demo.
- Create a workflows folder inside .github.
Your editor should now show the nested path .github/workflows/ inside the project.
- Create publish.yml inside .github/workflows/.
- Paste this workflow into .github/workflows/publish.yml:
name: Publish Package
# Publish only when a version tag is pushed.
on:
push:
tags:
- 'v*'
# Read the tagged commit and request a short-lived OIDC identity.
permissions:
contents: read
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
# Check out the commit referenced by the pushed tag.
- uses: actions/checkout@v6
# Configure Node.js for the public npm registry.
- uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false
# Publish without a stored npm token.
- run: npm publish --provenance
What does this workflow do?
- The 'v*' tag pattern starts the workflow when you push a version tag.
- The contents: read permission lets the checkout action read the tagged commit.
- The id-token: write permission lets the job request a short-lived OIDC identity.
- The setup action configures Node.js for the public npm registry.
- The final publish step creates a provenance record without reading an npm token secret.
- Save .github/workflows/publish.yml.
- Inspect the new file from the terminal by running:
git status --short
You should see the new workflow path listed as an untracked file. That confirms the file exists inside your repository.
Workflow file missing?
- Check that the full path is .github/workflows/publish.yml.
- Check that the filename ends with .yml.
- Check the YAML indentation if your editor highlights a syntax problem.
Ask for help: Help me check the path and YAML syntax in my GitHub Actions publish workflow.
✔️ Awesome, I've got everything!
Great. Double check that you saved .github/workflows/publish.yml before committing it.
ⓧ I'd like to double check the full code
Compare your complete workflow with this file.
name: Publish Package
# Publish only when a version tag is pushed.
on:
push:
tags:
- 'v*'
# Read the tagged commit and request a short-lived OIDC identity.
permissions:
contents: read
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
# Check out the commit referenced by the pushed tag.
- uses: actions/checkout@v6
# Configure Node.js for the public npm registry.
- uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false
# Publish without a stored npm token.
- run: npm publish --provenance
Commit the workflow
A Git commit makes the workflow part of the repository history. npm can then match the trusted publisher to a workflow that exists in the public repository.
- Stage the workflow by running:
git add .github/workflows/publish.yml
- Inspect the staged change by running:
git status --short
You should see .github/workflows/publish.yml listed as a staged file.
- Commit the staged workflow by running:
git commit -m "Add trusted publishing workflow"
You should see a commit summary containing Add trusted publishing workflow.
- Push the committed workflow to the repository by running:
git push origin HEAD
Your release automation is now part of the public repository. Anyone can inspect how future versions are published.
Push rejected?
- Check that the terminal is inside your local trusted-publish-demo repository.
- Confirm that your GitHub authentication still has permission to push to the repository.
- Read the final line of the terminal output for the specific branch or authentication problem.
Ask for help: Help me diagnose why my trusted publishing workflow will not push to GitHub.
Connect npm to the workflow
The workflow can request an OIDC identity. npm now needs the exact repository owner and workflow filename that are allowed to use that identity.
- Return to the npm package page from earlier.
- Select Settings on the package page.
- Find the Trusted Publisher section.
- Choose GitHub Actions under Select your publisher.
How does npm identify the workflow?
npm compares the OIDC claims from each publish job with the owner, repository, and workflow filename saved here. Each value must match the public GitHub repository exactly.
The npm form expects only publish.yml as the workflow filename. GitHub stores that file at .github/workflows/publish.yml.
- Enter <your-github-username> in Organization or user.
- Enter trusted-publish-demo in Repository.
- Enter publish.yml in Workflow filename.
- Leave Environment name blank.
- Enable npm publish under Allowed actions.
- Submit the completed form using the confirmation control at the bottom.
That is the trust boundary in place. npm now recognizes the GitHub repository and workflow you authorized.
Publisher details look wrong?
- Compare the repository owner with the public repository URL.
- Confirm that the repository value contains only trusted-publish-demo.
- Remove an incorrect connection from Trusted Publisher before creating the corrected connection.
Ask for help: Help me compare my npm trusted publisher fields with my GitHub repository and workflow.
Before you compare both pages, which repository and workflow details do you expect to match exactly?
- Return to the public trusted-publish-demo repository in GitHub.
- Open .github/workflows/publish.yml in the repository file browser.
- Confirm that the committed workflow grants id-token: write.
- Confirm that the workflow contains no secret reference for an npm token.
- Return to the package's Trusted Publisher section on npm.
- Confirm that the connection lists your GitHub owner with trusted-publish-demo.
- Confirm that the connection lists publish.yml as the workflow filename.
You should see the committed workflow at .github/workflows/publish.yml in GitHub. The npm connection should point to that same repository and filename.
Your repository and npm package now share a token-free trust relationship. Next, you will tag a new version and watch this workflow publish it with provenance.
Publish a Provenance Release
Your trusted publisher now connects npm to the publish workflow in your public GitHub repository. The final proof comes from a release accepted through GitHub Actions.
This release uses OIDC to authenticate version 1.0.1. The npm registry records that result as provenance.
In this step, get ready to:
- Create the release commit for 1.0.1 with tag v1.0.1.
- Trigger the trusted publishing workflow from the pushed tag.
- Verify the provenance record for version 1.0.1.
Create the 1.0.1 release
Semantic versioning uses the third number for a patch release. A patch bump changes 1.0.0 to 1.0.1.
The terminal from earlier should still point to the local trusted-publish-demo checkout containing package.json. npm handles the release bookkeeping as one version step.
- Bump the package's patch version by running this command:
npm version patch
What did npm change?
- The package.json file now records version 1.0.1.
- npm creates a Git commit for the version change.
- npm creates the local Git tag v1.0.1.
- Check the terminal output for v1.0.1.
- Return to package.json in your code editor.
- Confirm the version field now reads 1.0.1.
Version bump did not complete?
- Review pending changes in your Git client.
- Commit or discard those changes before retrying the version bump.
- Confirm the terminal is inside the trusted-publish-demo checkout containing package.json.
Ask for help: Why did my npm version bump fail before creating v1.0.1?
The release commit currently exists only in your local Git history. The public repository needs that commit before the release is complete.
- Push the version commit to GitHub by running this command:
git push
What does this push do?
The branch push sends the version commit to GitHub. This makes version 1.0.1 part of the public repository history.
- Check the terminal for confirmation that the branch was updated.
Commit push rejected?
- Confirm your network connection is active.
- Check that your Git authentication can write to the public repository.
- Confirm the local checkout still points to your GitHub repository.
Ask for help: Why is Git rejecting my version commit push?
Before you push the tag, do you expect GitHub Actions to start a release from v1.0.1?
- Send the local release tags to GitHub by running this command:
git push --tags
Why does the tag start publishing?
The tag push sends the newly created v1.0.1 tag to GitHub. The workflow in .github/workflows/publish.yml listens for version tags.
GitHub Actions now starts the publish run for the tagged commit. That commit contains package version 1.0.1.
- Check the terminal for confirmation that v1.0.1 reached GitHub.
Tag missing from the push?
- Confirm the version bump completed before the tag push.
- Check the terminal output from the version bump for v1.0.1.
- Retry the tag push after confirming the local tag exists.
Ask for help: Why did my v1.0.1 tag fail to reach GitHub?
Watch trusted publishing run
The pushed tag hands the release to the workflow from earlier. Its id-token: write permission lets GitHub request a short-lived identity for npm.
- Return to your trusted-publish-demo repository in the browser.
- Click Actions below the repository name.
- Select the newest workflow run for tag v1.0.1.
- Wait for the workflow run to finish.
You should see a successful workflow run for v1.0.1. The publish step completes after npm accepts the workflow's OIDC identity.
A successful run proves the trusted publisher accepted this workflow. The repository settings provide the second part of the check by showing that no publishing token was stored.
- Click Settings below the repository name.
- Select Secrets and variables in the security section.
- Select Actions.
- Select the Secrets tab.
- Confirm no repository secret is listed for npm publishing.
The missing publishing secret confirms the workflow did not rely on a stored npm token. GitHub supplied a temporary OIDC identity for this release.
What authenticated the publish?
GitHub generated a short-lived identity for this workflow run. npm checked that identity against the trusted publisher configuration for your repository and workflow file.
The identity expires after the run. There is no long-lived publishing credential waiting in the repository.
Workflow failed to publish?
- Confirm the trusted publisher names the same GitHub repository used by the workflow.
- Confirm the trusted publisher names workflow file .github/workflows/publish.yml.
- Confirm the workflow still grants id-token: write permission.
Ask for help: Why did npm reject my trusted publishing workflow?
Verify the published provenance
The package page is where the release becomes publicly auditable. Its provenance details connect the published package to the source commit and workflow run.
Before you refresh the package page, do you expect the registry to show the manual release or the new workflow release as the latest version?
- Return to your npm package page from earlier.
- Refresh the browser page.
You should see 1.0.1 in the Version field. A green provenance check mark appears beside it.
- Click the green check mark beside the Version field.
- Click View more details.
- Open the Build Summary link.
- Confirm the opened workflow run is the successful release for v1.0.1.
The provenance details link version 1.0.1 to its build environment and source commit. The Build Summary link returns you to the workflow run you just watched.
You made the release path work without a stored publishing token. Version 1.0.1 now carries a public record of the workflow that published it.
Secret mission
Audit the Tokenless Release Chain
Trace the published package from npm to its GitHub Actions run. Confirm the workflow used OIDC without a stored publishing secret.
Clean Up Your Resources
Clean Up Your Resources
Choose whether to keep the public resources available, pause future automated releases, or retire the project. The public GitHub repository and public npm package can stay online at no cost.
Remove the manual publishing credential
Trusted publishing handles future releases without a stored npm token. Any credential used for the initial manual publish has finished its job.
Resources you used:
- Public GitHub repository <your-github-username>/trusted-publish-demo.
- Public npm package @<your-npm-username>/trusted-publish-demo with versions 1.0.0 and 1.0.1.
- Trusted publisher configuration for repository <your-github-username>/trusted-publish-demo and workflow .github/workflows/publish.yml.
- Any npm CLI credential used for the initial manual publish.
Keep everything running
No hosted resource needs to be removed. Choose this option if you want to keep publishing new versions through the trusted workflow.
- Leave the public GitHub repository <your-github-username>/trusted-publish-demo available.
- Leave the npm package @<your-npm-username>/trusted-publish-demo available.
- Keep the trusted publisher configuration connected to .github/workflows/publish.yml.
- Revoke any npm token associated with the initial manual publish from your npm account's access token page.
- Confirm that the repository's secret settings contain no npm publishing token.
Your next version tag can still trigger a trusted publish. The retired manual credential cannot be reused.
Pause - I'll come back to this later
There is no continuously running process to stop. Pausing means disconnecting the trusted workflow while preserving the repository and published versions.
- Return to the trusted publishing configuration for @<your-npm-username>/trusted-publish-demo on npm.
- Remove the configuration that trusts repository <your-github-username>/trusted-publish-demo.
- Confirm that no trusted publisher entry names .github/workflows/publish.yml.
- Leave the public GitHub repository available.
- Leave versions 1.0.0 and 1.0.1 available on npm.
- Revoke any npm token associated with the initial manual publish from your npm account's access token page.
The repository and published versions remain available for your return. New workflow runs no longer have trusted publishing permission.
Delete - I don't want to use this again
Retire the package and remove its publishing access. The published versions remain part of the public registry with a deprecation notice.
- Return to the trusted publishing configuration for @<your-npm-username>/trusted-publish-demo on npm.
- Remove the configuration that trusts repository <your-github-username>/trusted-publish-demo.
- Confirm that no trusted publisher entry names .github/workflows/publish.yml.
- Deprecate every published version of @<your-npm-username>/trusted-publish-demo from its npm package settings.
- Confirm that versions 1.0.0 and 1.0.1 display a deprecation notice.
- Use the permanent repository deletion controls in the settings for <your-github-username>/trusted-publish-demo.
- Confirm that the deleted repository URL is no longer available.
- Revoke any npm token associated with the initial manual publish from your npm account's access token page.
What stays on npm?
Deprecation preserves the published versions with a warning for future visitors. Removing the trusted publisher prevents the deleted workflow from receiving publish access.
Nice Work!
Nice Work!
Excellent work. You published a real package to npm through GitHub Actions without storing a long-lived release token in the repository. Version 1.0.1 now displays a provenance badge that traces the release to its source workflow.
You learned how to:
- Built a tiny public package with an executable command that prints a success message in the terminal.
- Published 1.0.0 manually to establish the package on npm. Configured trusted publishing for <your-github-username>/trusted-publish-demo using .github/workflows/publish.yml.
- Triggered the token-free release by pushing the v1.0.1 tag. Verified the provenance badge with no npm publishing secret in the GitHub repository.
- Secret Mission: Completed the optional challenge to push your package publishing skills further.
Ready to quiz yourself?