Github actions, 401 unauthorized when installing a Github Package with npm or yarn

50.8k views Asked by At

When I try to install my npm modules from a GitHub action I get the following error:

npm ERR! 401 Unauthorized - GET https://npm.pkg.github.com/@xxxx%2fxxxx-analytics - Your request could not be authenticated by the GitHub Packages service. Please ensure your access token is valid and has the appropriate scopes configured.

Before you comment, I have configured the .npmrc correctly with the scope and access token, and everything works fine when installing the private package locally.

Here is my GitHub workflow action:

name: JavaScript workflow

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js 12.x
        uses: actions/setup-node@v1
        with:
          node-version: '12.x'
      - name: npmrc
        run: cat .npmrc
      - name: npm install
        run: |
          npm install
        env:
          CI: true
          NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

here is my .npmrc

@fortawesome:registry=https://npm.fontawesome.com/
//npm.fontawesome.com/:_authToken=XXXXXXXXX
@colonynetworks:registry=https://npm.pkg.github.com
//npm.pkg.github.com:_authToken=XXXXXXXXX
always-auth=true
@react-admin:registry=https://registry.marmelab.com
//registry.marmelab.com:
_auth=XXXXXXXXX
[email protected]
always-auth=true

It's a private repo and the authTokens are currently hardcoded in the .npmrc file.

However while trying to find a solution for this, I did come across this random comment from a Github staff member: https://github.community/t/netlify-getting-401-from-github-package-registry-with-auth-token/16415/3

It's a bit vague, but it sounds like it doesn't accept a hardcoded authToken in the .npmrc file.

So first thing I tried was to use our env variable instead like so:

@xxxx=https://npm.pkg.github.com
//npm.pkg.github.com:_authToken=${NPM_AUTH_TOKEN}

The env variable is correct in our Github repo secrets, and supplied by the workflow.

However this still resulted in the same 401 Unauthorized error.

From looking at other solutions I then tried to generate the .npmrc manually inside the Github action before the install step, like so:

- name: npmrcgen
        run: |
          echo "//npm.pkg.github.com/:_authToken=XXXXXXX" > .npmrc
          echo "@xxxxx=https://npm.pkg.github.com/" >> .npmrc
          echo "@react-admin:registry=https://registry.marmelab.com" >> .npmrc
          echo "//registry.marmelab.com:" >> .npmrc
          echo "_auth=XXXXXXX" >> .npmrc
          echo "[email protected]" >> .npmrc
          echo "always-auth=true" >> .npmrc

During the logging step I added, it the _authToken (only for Github) still shows up as ***, and I still got a 401 Unauthorized error.

At this point I wanted to confirm the .npmrc was even being used, so I removed the second private registry we used for marmelab.com, and sure enough, I got an error saying it was no longer able to install their ra-realtime package. This proves the .npmrc file is indeed being read and used by my Github action, but it's not accepting my Github personal access token.

I have tried to generate a new token as well. It has full access to everything under repo: as well as write:packages and read:packages which is what should be required.

Still 401 Unauthorized in the Github action, and still works fine locally.

Lastly I have tried to install it with yarn instead of npm. Unsurprisingly this did not fix it either.

I have seen and tried the following solutions without any success:

One thing I have not tried, as I have seen no recommendations on how or this being a good idea, but I have not done an npm login within the Github action. Since no one else has done this, and somehow have it working, I assume this is not necessary.

5

There are 5 answers

1
MLyck On BEST ANSWER

I contacted GitHub support and they managed to figure out what the problem was.

Github workflows are more strict than local environments and require an extra / before the auth token:

spot the difference:

//npm.pkg.github.com:_authToken=XXXXXXXXX. # broken
//npm.pkg.github.com/:_authToken=XXXXXXXXX # works

adding the extra / before :_authToken= solved the issue for me.

3
Atur On

Have a .npmrc file in root of your project.

Content of .npmrc:

registry=https://registry.npmjs.org/
@{scope}:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=********** (Token generated from github)

@{scope} is your organization-name or your username. It is case-sensitive.

0
David Moles On

Addendum for anyone else who, like me, runs across this question outside the context of GitHub Actions: note that the GitHub package registry uses HTTP Basic Authentication. So if you're trying to test a personal access token and don't want to mess with your .npmrc / .yarnrc, you can pass the credentials in the registry URL, e.g. with yarn:

yarn info "@<github-org>/<repo-name>" \
     --registry="https://<github-user>:<token>@npm.pkg.github.com/"

Or with curl:

curl -vL 'http://<github-user>:<token>@npm.pkg.github.com/@<github-org>%2f<repo-name>'
1
Armen Nagapetian On

This problem is happening due to Visibility access, to be able to delete packages you need Admin Permission. enter image description here

Even when trying to do this by separate method without github Actions you still need Admin Permission for deletion.

even when you want to use other methods to Delete packages such as following code below, You still need Admin Permissions and PAT token to do so with delete:packages permissions.

I’ve written the kind of cleanup script I was thinking of here using the new packages delete/restore API .

I had a similar thought.

Here’s a GitHub Action script that can be used to delete untagged images for a specified container package:

  - uses: actions/github-script@v3
    with:
      github-token: ${{ secrets.DELETE_PACKAGES_TOKEN }}
      script: |
        const response = await github.request("GET /${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions",
          { per_page: ${{ env.PER_PAGE }}
        });
        for(version of response.data) {
            if (version.metadata.container.tags.length == 0) {
                console.log("delete " + version.id)
                const deleteResponse = await github.request("DELETE /${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions/" + version.id, { });
                console.log("status " + deleteResponse.status)
            }
        }
    env:
      OWNER: user # or orgs/<org name>
      PACKAGE_NAME: <package name>
      PER_PAGE: 100

OWNER should be either a user name or orgs/ORG_NAME. DELETE_PACKAGES_TOKEN is a PAT with the delete:packages and write:packages scopes.

2
Heng On

Just use actions/setup-node action.

- uses: actions/setup-node@v3
  with:
    node-version: 16
    cache: "yarn"
    registry-url: "https://npm.pkg.github.com"

- name: Build
  env:
    # also other environment variable
    NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    yarn
    yarn build