Npm registry authentication

Hello Package Manager users!

Starting from Unity 2019.3.4f1, you’ll be able to configure NPM authentication for your scoped registries. This is a feature that was heavily requested by our enterprise customers.

Attention: Before we explain how to configure your authentication token, I just want to warn we are making this feature available in its MVP form to unblock some of you. That means, a couple of manual operations are required (i.e. not really user-friendly). The end goal is to expose a login UI in the Hub. Users will only have to enter their credentials and the rest would be taken care of.

Below, I copied the internal draft documentation sent to our technical writer to be added to the Unity user manual. Please note this will be greatly re-formatted and improved when finalized.


Introduction

The introduction of scoped registries enabled enterprise users to share their own custom packages inside their studio. For most studios and companies, anonymous access within a local network is sufficient to fulfill their security requirements. Nevertheless, some users want more control and enable authentication on a user base. Most off-the-shelve or open-source registry solutions support npm authentication through a persistent token. This document explains how to configure UPM to enable this feature.

Feature availability

The feature was introduced in Unity 2019.3.4f1 and 2020.1.0a25.

Manual login

Users will need to fetch their authentication token via npm command-line interface and manually copy and paste the token in UPM global configuration file.

1) Fetch the npm authentication token

Warning: Inconsistent login flow across vendors
Registry vendors may have different login flow. The login procedure described below is the official npm login flow. Some vendors, like JFrog (Bintray and Artifactory), require different steps to generate the authentication token. Please, consult their respective documentation to make sure you go through the proper process to fetch the token.

  1. Install npm locally on your machine.
  2. Login to the registry using the npm login command-line. In a terminal type this command:

npm login --registry <registry url>

  1. Locate the generated .npmrc file.
  2. Open the .npmrc file. Extract the token (look for the AUTH_TOKEN label in the examples below. Depending on the registry, the token string will be different (guid, token, or a proprietary formatted string).

Here are some examples of .npmrc files:

.npmrc with _authToken attribute

registry=https://registry.com:1234/pathname/
//registry.com:1234/pathname/:_authToken=<AUTH TOKEN>

.npmrc with _auth attribute (Base64 encoded)

registry=https://registry.com:1234/pathname
_auth=<AUTH TOKEN>
email=<EMAIL>
always-auth=true

2) Create a Unity Package Manager user configuration file

This section explains how to set up UPM configuration so every request made to the registry includes proper authentication information.

2.1) Unity Package Manager user configuration file location

Locate .upmconfig.toml in your home directory:

Windows: %USERPROFILE%/.upmconfig.toml (Usually %SystemDrive%\Users<your username>/.upmconfig.toml)
Windows (System user) : %ALLUSERSPROFILE%Unity/config/ServiceAccounts/.upmconfig.toml
MacOS and Linux: ~/.upmconfig.toml (usually /Users//.upmconfig.toml)

If the file does not already exist, create one.

2.2) User configuration file schema

2.2.1 Schema
This is the schema for the configuration npmAuth attribute:

Token based authentication (Bearer)

[npmAuth."<REGISTRY URL>"]
token = "<AUTH TOKEN _authToken in .npmrc)>"
email = "<EMAIL>"
alwaysAuth = <BOOLEAN>

Base64 authentication (Basic)

[npmAuth."<REGISTRY URL>"]
_auth = "<BASE64 ENCODED TOKEN (_auth in .npmrc)>"
email = "<EMAIL>"
alwaysAuth = <BOOLEAN>

2.2.1 Details

registry-url (required) : Url for the registry (ex: https://my.registry:8081/some/path) .
token or _auth (required): The authentication token generated from login to the npm registry. See the previous section to understand how to generate and fetch the token.
email (optional): User email.
alwaysAuth (optional): Set to true if the package metadata and tarballs and not located on the same server. Typically, you’ll copy the value from the generated .npmrc if present (see the previous section).

2.2.2 Example

[npmAuth."http://localhost:8081/repository/test"]
token = "NpmToken.2348c7ea-6f86-3dbe-86b6-f257e86569a8"
alwaysAuth = true
[npmAuth."http://localhost:4873"]
token = "eaJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWFsX2dyb3VwcyI6WyJwYXNjYWxsIl0sIm5hbWUiOiJwYXNjYWxsIiwiZ3JvdXBzIjpbInBhc2NhbGwiLCIkYWxsIiwiJGF1dGhlbnRpY2F0ZWQiLCJAYWxsIiwiQGF1dGhlbnRpY2F0ZWQiLCJhbGwiLCJwYXNjYWxsIl0sImlhdCI6MTU3NDY4ODQ5MCwibmJmIjoxNTc0Njg4NDkxLCJleHAiOjE1Nzk4NzI0OTB9.qF8_0ue1ppraWLkReT06AMG6R7RZuDiV2XinxMkdSo0"
"
[npmAuth."https://api.bintray.com/npm/joe-company/my-registry"]
token = "aGFzY2FsbDo4ZWIwNTM5NzBjNTI3OTIwYjQ4MDVkYzY2YWEzNmQxOTkyNDYzZjky"
email = "joe@company.com"
alwaysAuth = true

[npmAuth."https://base64.registry.com"]
_auth = "aGFzY2FsbDo4ZWIwNTM5NzBjNTI3OTIwYjQ4MDVkYzY2YWEzNmQxOTkyNDYzZjky"
email = "joe@company.com"
alwaysAuth = true

Again, really sorry about the crude/raw form of this feature for the moment but I hope this will still be helpful for some of you.

Pascal

16 Likes

awesome, thanks! hoping 2019.3.4f1 will land today

Great to see this land!

Have you considered adding project-based authentication, like the undocumented “_auth” property in the project manifest allowed in earlier Unity versions?

Use case: When collaborating on a Unity project with others, who are not necessarily technically versed, I would like to make the process of checking out the project as frictionless as possible. Including a repository token directly in the project’s manifest, people with access to the Git repository would simply be able to check out and use the project, without having to worry about logging in to the repository and managing separate login credentials.

I’m not too worried about sharing the token with everyone in the project, Git authentication already limits access and the token can be invalidated/updated when needed.

Having a GUI in Unity for logging into the registry and/or adding support for scoped registries from GitHub/GitLab would alleviate some of the friction but project-level authentication would still make the setup easier.

This could be achieved with a configuration in the project’s manifest or by having the package manager check for a configuration file inside the project folder first.

6 Likes

Hello,

I tried this out, but I am getting the following error:

I am able to do npm install com.domain.package.

I created a .upmconfig.toml file and set it up like so:

[npmAuth."https://nexus3.domain.com/repository/repo/"]
token = "SAME_TOKEN_THATS_IN_NPMRC="
email = "email@domain.com"
alwaysAuth = true

I couldn’t find any useful logs. Any help would be amazing, thanks!

I had the same issue as @toeadd31 with a Nexus repository. I tried Verdaccio with authentication, and curiously the version 1.0.0 of my package was downloaded fine. But version 1.0.1 wouldn’t download. I restarted Unity, but still had same issue. Log message said it “failed because it lacks valid authentication credentials”.

I wonder if Unity caches some authentication information. I placed a wrong authToken in the .upmconfig.toml file, and I’d get the same behaviour (even after restarting Unity).

It would be great if we had extra logs/information on the error. I was using Unity 2019.3.4f1.

We don’t cache the auth information. We read the configuration file on every request.

Let me try with Nexus again and see if I can repro. I’ll keep you posted.

Pascal

You need to delete slash at the end of the registry URL

[npmAuth."https://nexus3.domain.com/repository/repo"]

Good catch! Indeed, the npmAuth and scoped registry url must match perfectly for the token to be used when a request is sent to the NPM registry.

@ok_torresmo @toeadd31 Can you validate both attribute have the exact same URL?

Pascal

Hello,

I have tested a few ways, I tested both with and both without a slash. I also tested the NpmToken. style token and the base64 username:password style token.

Nothing seems to work for me. I keep getting the same error.

I would assume I am just missing something? This is pointing to a nexus3 private repo with a hosted npm format.

Thanks again!
Todd

Has anyone gotten this to work with Azure DevOp’s NPM artifact stream? Tried with a slash at the end and without as mentioned above, tried also the PAT token base64 encoded and not. Each way has resulted in the lacks valid authentication credentials message.

Ok, I got it working. Yeah, you need to make sure the URL is the same (even though the slash does not seem to make a difference). I guess my issue was a stupid mistake on my side (upmconfig had a ‘https’ URL, manifest had ‘http’ URL). Also make sure you are grabbing the correct token from the .npmrc file, because in my case it contained a couple auth tokens for the same repo (but slightly different urls).

1 Like

Hey everyone,

I made a mistake in my doc. I forgot to document the base64 based Basic authentication schema. This may be one reason why it doesn’t work for some of you. Here the proper schema for that use case:

[npmAuth."<REGISTRY URL>"]
_auth = "<BASE64 ENCODED TOKEN>"
email = "<EMAIL>"
alwaysAuth = <BOOLEAN>

Notice the _auth attribute instead of token
I’ll update my original post. Sorry about this!

Pascal

What does the package manager error unable to get local issuer certificate mean in this situation? I haven’t been able to get this to work, and I’m not sure if it’s because something is configured incorrectly, or if it is because Unity is not finding the config file. Is there any way to verify where exactly Unity is looking?

Looks like the specific error in upm.log is

{
  "message": "unable to get local issuer certificate",
  "stack": "Error: unable to get local issuer certificate\n    at TLSSocket.onConnectSecure (_tls_wrap.js:1285:34)\n    at TLSSocket.emit (events.js:196:13)\n    at TLSSocket.EventEmitter.emit (domain.js:494:23)\n    at TLSSocket._finishInit (_tls_wrap.js:758:8)\n    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:590:12)",
  "code": "UNABLE_TO_GET_ISSUER_CERT_LOCALLY"
}

Ah, yep that was my issue, thanks!

Also having trouble getting this to work using an Azure DevOps NPM Artifacts Feed.
Have tried all of the same things as @z000z but also getting the “lacks valid authentication credentials” message.
Would be fantastic to find a solution to this :frowning:

This means the certificate cannot be verified with an approved certificate authority. Probably your network is configured with a proxy decrypting the messages and re-encrypting them with its own certificate (hence the local issuer error). You need to configure your own certificate authority. This is documented here.

Pascal

Have you tried to use the Basic auth configuration instead? See my post about the missing documentation here .

Pascal

Hi @okcompute_unity .

Yes, just as @z000z has mentioned, I have tried:

  • With and without a trailing slash in the registry url (double-checking to make sure they were identical in the .upmconfig.toml file and in the manifest file)
  • Using the token generated via logging into the registry
  • Generating a PAT token manually on my Azure DevOps account, Base64 encoding it and adding it to .upmconfig.toml file with the “_auth” property name (also tried using the “token” property)
  • Tried using the PAT token again but without encoding it in Base64
  • Added the .upmconfig.toml file to the %USERPROFILE% directory AND the %ALLUSERSPROFILE%Unity/config/ServiceAccounts directory

Still, having tried everything above, I get the “lacks valid authentication credentials” message :frowning:

Any help is greatly appreciated!

Also tried the _auth suggestion, but still ran into the credentials problem. Using a Mac so have the file in the ~/ folder, but otherwise same as @Darzer

As an update to this, I have installed Verdaccio locally and set my Azure DevOps NPM Artifact feed as an Uplink.
In the config file where that Uplink is defined, I added my bearer token (the one generated previously) inline.
I then setup a proxy for package requests starting with my feed namespace (like com.XYZ.*) to that Uplinked feed.

Having done the above, I simply changed my manifest.json file to point to Verdaccio on localhost and it managed to resolve my package!

Considering that Verdaccio is essentially “wrapping” around my hosted NPM feed as a proxy, I am surprised that it works, whereas attempting to go directly to my hosted feed fails. And seeing as the bearer token I’m using is the very same one I’ve defined in my .upmconfig.toml file I am perplexed.

Perhaps my .upmconfig.toml file is not even being found by Unity? I say this because it doesn’t seem to matter what the contents of it are, I always get the “lacks valid authentication credentials” message (even if I delete the contents of .upmconfig.toml completely).

Hopefully this helps you @Ok_Computer with any debugging you may be doing.
It would be great to be able to resolve packages directly through my Azure DevOps feed but this workaround is perfect for the time being :slight_smile: