berry: [Bug] Azure artifacts authentication

Describe the issue

Really not sure this is a bug; more like a support question. I am having trouble getting my Azure DevOps Artifacts npm registry working with berry. It works fine in v1, using the token from .npmrc, which is generated by Azure DevOps.

The “<server>:_password” field in the .npmrc is a base64 encoded Personal Access Token generated in Azure DevOps, and according to their documentation, the “:username” and “:email” field mean nothing. Documentation is found here

I have tried generating the auth token through their Artifact “Connect to feed” process, which generates the token for your .npmrc like this

; Treat this auth token like a password. Do not share it with anyone, including Microsoft support. This token expires on or before 10/10/2019.
; begin auth token
//pkgs.dev.azure.com/<organization>/_packaging/<artifact feed>/npm/registry/:username=<username removed.  It was the name of my organization or feed... they are the same>
//pkgs.dev.azure.com/<organization>/_packaging/<artifact feed>/npm/registry/:_password=<password removed>
//pkgs.dev.azure.com/<organization>/_packaging/<artifact feed>/npm/registry/:email=npm requires email to be set but doesn't use the value
//pkgs.dev.azure.com/<organization>/_packaging/<artifact feed>/npm/:username=<username removed>
//pkgs.dev.azure.com/<organization>/_packaging/<artifact feed>/npm/:_password=<password removed>
//pkgs.dev.azure.com/<organization>/_packaging/<artifact feed>/npm/:email=npm requires email to be set but doesn't use the value
; end auth token

I also tried generating my own PAT, and base64 encoding it, for use in that “_password” field.

I used that “_password” field as the npmAuthToken in my .yarnrc.yml, I’ve tried using it in the npmAuthIdent in combination with the username from above, as <username>:<token>. I’ve tried combining the <username>:<token> into a base64 encoded string and including that in the npmAuthToken. None of these work. I always get (401) Unauthorized.

To Reproduce

You would need a module published in an Azure DevOps Artifacts registry.

My .yarnrc.yml is below, with the sensitive information redacted.

npmRegistries:
  //pkgs.dev.azure.com/<organization>/_packaging/<azurefeed>/npm/registry:
    npmAlwaysAuth: true
    npmAuthToken: "<_password field from above>"
  //pkgs.dev.azure.com/<organization>/_packaging/<azurefeed>/npm:
    npmAlwaysAuth: true
    npmAuthToken: "<_password field from above>"

npmScopes:
  <org>:
    npmRegistryServer: https://pkgs.dev.azure.com/<organization>/_packaging/<azurefeed>/npm/registry

Environment if relevant (please complete the following information):

  • OS: Linux
  • Node version: v12.6.0
  • Yarn version: v2.0.0

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 20 (12 by maintainers)

Most upvoted comments

For future readers - tldr: To connect to Azure Artifacts:

npmRegistryServer: "https://your-server"
npmAuthIdent: "base64(your-org:your-pat)"

your-pat is probably encoded as base64 in your ~/.npmrc file. You’ll need to decode it first. before re-encoding the key.

To clarify this even more:

  1. Follow the “Connect to feed”, “NPM” instructions to generate a PAT token Screenshot 2022-06-24 at 15 54 26

But in step 3.2, type:

<organisation>:<PAT>

Then your .yarnrc.yml should look like this (replace <...> with your values):

npmRegistries:
  //pkgs.dev.azure.com/<organisation>/_packaging/<azurefeed>/npm/registry:
    npmAlwaysAuth: true
    npmAuthIdent: <base64 output from above>

npmScopes:
 <azurefeed>:
    npmRegistryServer: "https://pkgs.dev.azure.com/<organisation>/_packaging/<azurefeed>/npm/registry"

After you have this setup, yarn npm info @scope/@mypackage should work!

I’ve tested this with yarn berry/v3.

Problem still exists, lacks of solution. Are we able to provide more details, any kind of yarnrc.yml as example?

for us the base64 encoding did not work, but having the <org>:<pat> in plain form in the npmAuthIdent did

I put a console.log in there, but it only reported anything during the resolution stage, and those are successful (return code 200). Then it fails during the fetch stage with the 400 error (Authentication information is not given in the correct format. Check the value of Authorization header.), and the console.log doesn’t get hit at all. This is on my Windows machine at work.

I will try this again on my Linux box tonight to get some logs for that 401 (Unauthorized) error.

I realized what I’ve been doing wrong with npmAuthIdent after replicating the process with curl. curl, by default, base64 encodes the string that you pass to the -u option. That made me realize that I’ve been encoding the field npmAuthIdent wrong this entire time. I have been encoding the PAT, but leaving the rest like username:<encoded PAT>, which looking at now makes no sense. I had also tried encoding the entire string, but only after I had already encoded the PAT… 🙄

So, after encoding <username>:<raw PAT> as base64, and putting that in the npmAuthIdent, I successfully authenticate with the server. So now I don’t need the npmAuthToken (which would be too complicated to get for use on my Linux box). However, I am still getting the 400 (Authentication information is not given in the correct format. Check the value of Authorization header.) error. I do think it is expecting an email field, even if it doesn’t mean anything.

Here’s what I got from curl…

  1. Hit the address that was being used as the target in the HttpUtil.
    • Got the JSON content for the package in question
  2. Hit the tarball URL retrieved from the JSON
*   Trying 13.107.42.20...
* TCP_NODELAY set
* Connected to pkgs.dev.azure.com (13.107.42.20) port 443 (#0)
(SSL/TLS handshake omitted for brevity)
* Server auth using Basic with user '<my email address>'
> GET /<organization>/_packaging/<feed>/npm/registry/@<scope>/<package>/-/<package>-1.2.0.tgz HTTP/1.1
> Host: pkgs.dev.azure.com
> Authorization: Basic <base64 encoded <email:personal access token>
> User-Agent: curl/7.55.1
> Accept: */*
(schannel output omitted for brevity)
< HTTP/1.1 302 Found
< Cache-Control: no-cache
< Pragma: no-cache
< Expires: -1
< Location: https://1yovsblobprodeus2184.blob.core.windows.net/<server/relative/path>.blob?<package query>
< P3P: CP="CAO DSP COR ADMa DEV CONo TELo CUR PSA PSD TAI IVDo OUR SAMi BUS DEM NAV STA UNI COM INT PHY ONL FIN PUR LOC CNT"
< X-TFS-ProcessId: b2b4c5ab-39f3-4afb-abb8-099a15970b28
< Strict-Transport-Security: max-age=31536000; includeSubDomains
< ActivityId: 31953bf3-1506-4218-a267-8131454236f4
< X-TFS-Session: 31953bf3-1506-4218-a267-8131454236f4
< X-VSS-E2EID: 31953bf3-1506-4218-a267-8131454236f4
< X-VSS-UserData: <my user data>
< X-FRAME-OPTIONS: SAMEORIGIN
< Request-Context: appId=cid-v1:aafc8b1a-8b8b-40da-82f7-2e27c159556b
< Access-Control-Expose-Headers: Request-Context
< X-Content-Type-Options: nosniff
< X-MSEdge-Ref: Ref A: A41A8C44161C4BCEA1C27C42B3941EC9 Ref B: HNL01EDGE0213 Ref C: 2019-07-31T23:45:47Z
< Date: Wed, 31 Jul 2019 23:45:47 GMT
< Content-Length: 0
<
* Connection #0 to host pkgs.dev.azure.com left intact
  1. Hit the file Location response, and this is what I get
*   Trying 52.179.144.64...
* TCP_NODELAY set
* Connected to 1yovsblobprodeus2184.blob.core.windows.net (52.179.144.64) port 443 (#0)
(SSL/TLS handshake omitted for brevity)
* Server auth using Basic with user '<my username (email)>'
> GET <server/relative/path>.blob?<package query> HTTP/1.1
> Host: 1yovsblobprodeus2184.blob.core.windows.net
> Authorization: Basic <base64 encoded <email:personal access token>>
> User-Agent: curl/7.55.1
> Accept: */*
>
(schannel output omitted for brevity)
< HTTP/1.1 400 Authentication information is not given in the correct format. Check the value of Authorization header.
< Content-Length: 298
< Content-Type: application/xml
< Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
< x-ms-request-id: 6079e633-601e-0064-19fa-4731fa000000
< Date: Wed, 31 Jul 2019 23:46:23 GMT
<
<?xml version="1.0" encoding="utf-8"?>
<Error><Code>InvalidAuthenticationInfo</Code><Message>Authentication information is not given in the correct format. Check the value of Authorization header.
RequestId:6079e633-601e-0064-19fa-4731fa000000
Time:2019-07-31T23:46:23.6899938Z</Message></Error>* Connection #0 to host 1yovsblobprodeus2184.blob.core.windows.net left intact

Where does an npm server usually expect to see the email address in the request? I can run that through curl, and if I am able to retrieve the tarball, we know that’s the problem.

For future readers - tldr: To connect to Azure Artifacts:

npmRegistryServer: "https://your-server"
npmAuthIdent: "base64(your-org:your-pat)"

your-pat is probably encoded as base64 in your ~/.npmrc file. You’ll need to decode it first. before re-encoding the key.

THANK YOU @darthtrevino ! This just worked for me using github registry as well. Finally!

Then your .yarnrc.yml should look like this (replace <...> with your values):

npmRegistries:
  //pkgs.dev.azure.com/<organisation>/_packaging/<azurefeed>/npm/registry:
    npmAlwaysAuth: true
    npmAuthIdent: <base64 output from above>

npmScopes:
 <azurefeed>:
    npmRegistryServer: "https://pkgs.dev.azure.com/<organisation>/_packaging/<azurefeed>/npm/registry"

In case anyone else has a similar setup to me, we run all modules through our azure registry, so our shared .yarnrc.yml looked like this:

npmRegistryServer: "https://pkgs.dev.azure.com/<org>/_packaging/<feed>/npm/registry/"

npmRegistries:
  //pkgs.dev.azure.com/<org>/_packaging/<feed>/npm/registry/:
    npmAlwaysAuth: true
    npmAuthIdent: "<org>:${AZURE_ARTIFACTS_TOKEN}"

And then each dev can have their own $AZURE_ARTIFACTS_TOKEN in their PATH, and it’s easy to set the env var in a build