36

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=software@XXXXXXXXX.com
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=software@xxxxx.com" >> .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.

RobC
  • 22,977
  • 20
  • 73
  • 80
MLyck
  • 4,959
  • 13
  • 43
  • 74
  • 1
    No solution, but similar (same) issue: https://stackoverflow.com/questions/60346132/github-actions-unable-to-install-private-gpr-npm-package – riQQ Oct 06 '20 at 18:58
  • 1
    @riQQ please let me know if you find a solution. I submitted a bounty on this question, but still nothing. Also sent a support ticket to Github, but still waiting for a response. – MLyck Oct 07 '20 at 17:17
  • GitHub replied to my support request saying my setup looks correct, and requested access to the private repo I'm publishing my package from :( No solution yet, but they're saying it migt be related to the published package and not the install step. – MLyck Oct 08 '20 at 15:20
  • Could you try writing your .npmrc file to your user home directory i.e. ~/.npmrc? – Oluwafemi Sule Oct 12 '20 at 07:46
  • how about using github creds ,like username (not email) and password ? – NiNiCkNaMe Oct 12 '20 at 16:41

5 Answers5

27

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.

MLyck
  • 4,959
  • 13
  • 43
  • 74
  • Could you add the complete working version, that you finally used, to the question thread or herein as a solution? Would be very helpful, kind regard. – Ndrslmpk Dec 21 '22 at 11:52
12

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.

Atur
  • 1,712
  • 6
  • 32
  • 42
  • what should be the @{scope} if my repo is on GitHub enterprise? – Yasser Shaikh Aug 25 '21 at 05:17
  • @YasserShaikh it should be your organisation's name, e.g. for this repo https://github.com/microsoft/TypeScript it would be `@microsoft` – aaimio Jan 12 '22 at 10:52
  • 1
    But why do you use `registry=https://registry.npmjs.org/` as registry, when you use github as package registry? – Ndrslmpk Dec 21 '22 at 11:59
1

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>'
David Moles
  • 48,006
  • 27
  • 136
  • 235
0

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
Heng
  • 52
  • 1
0

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.

Hasitha Jayawardana
  • 2,326
  • 4
  • 18
  • 36