berry: yarn 3 ignores npmAuthTokens in ~/.yarnrc.yml: "Invalid authentication (as an anonymous user)" when using private repo, despite `yarn npm login`
TL;DR: yarn 3.2.0 seems to ignore auth tokens in $HOME/.yarnrc.yml, since the token generated by yarn npm login has to be manually added to $PROJECT/.yarnrc.yml to authenticate when doing yarn install. There’s a reproduction script at the end!
I’m trying to upgrade a project from yarn 1.x to modern yarn using the migration checklist, and I’m running into trouble at the step where I run yarn install:
- Run npm install -g yarn to update the global yarn version to latest v1
- Go into your project directory
- Run yarn set version berry to enable v2 (cf Install for more details)
- If you used .npmrc or .yarnrc, you’ll need to turn them into the new format (see also 1, 2)
- Add nodeLinker: node-modules in your .yarnrc.yml file
- Commit the changes so far (yarn-X.Y.Z.js, .yarnrc.yml, …)
- Run yarn install to migrate the lockfile
We install all modules from a private Nexus repository, which houses our private packages while also acting as a proxy to the public NPM repo. This Nexus repo requires authentication at all times, which is where the troubles begin.
This is the project’s .yarnrc.yml:
yarnPath: .yarn/releases/yarn-3.2.0.cjs
nodeLinker: node-modules
npmRegistryServer: "https://nexus.example.com/repository/npm-all"
npmAlwaysAuth: true
npmRegistries:
"https://nexus.example.com/repository/npm-all":
npmAlwaysAuth: true
If I try to install without logging in, it predictably fails since I haven’t logged in to the Nexus server:
$ yarn install
➤ YN0000: ┌ Resolution step
➤ YN0041: │ @testing-library/jest-dom@npm:5.16.4: Invalid authentication (as an anonymous user)
➤ YN0000: └ Completed in 0s 513ms
➤ YN0000: Failed with errors in 0s 521ms
So I login:
$ yarn npm login
➤ YN0000: Logging in to https://nexus.example.com/repository/npm-all
✔ Username: · my-name
✔ Password: · ****************
➤ YN0000: Successfully logged in
➤ YN0000: Done in 17s 175ms
Seems to have gone well, and it has generated a $HOME/.yarnrc.yml:
npmRegistries:
"https://nexus.example.com/repository/npm-all":
npmAuthToken: NpmToken.00000000-1111-2222-3333-444444444444
But yarn install still fails, and I actually don’t seem to be logged in:
$ yarn install
➤ YN0000: ┌ Resolution step
➤ YN0041: │ @testing-library/jest-dom@npm:5.16.4: Invalid authentication (as an anonymous user)
➤ YN0000: └ Completed in 0s 523ms
➤ YN0000: Failed with errors in 0s 532ms
$ yarn npm whoami
➤ YN0033: No authentication configured for request
➤ YN0000: Failed with errors in 0s 4ms
The only workaround I’ve found is copying the npmAuthToken from $HOME/.yarnrc.yml to $PROJECT/.yarnrc.yml:
$ cat $PROJECT/.yarnrc.yml
yarnPath: .yarn/releases/yarn-3.2.0.cjs
nodeLinker: node-modules
npmRegistryServer: "https://nexus.example.com/repository/npm-all"
npmAlwaysAuth: true
npmRegistries:
"https://nexus.example.com/repository/npm-all":
npmAuthToken: NpmToken.00000000-1111-2222-3333-444444444444
npmAlwaysAuth: true
$ yarn npm whoami
➤ YN0000: my-name
➤ YN0000: Done in 0s 74ms
This is obviously not something I want to do. How can I tell yarn to use the auth token that yarn npm login creates?
Versions used:
$ yarn -v
3.2.0
$ node -v
v14.16.0
EDIT: So I managed to set up a script that reproduces this issue. It starts a new Nexus server through docker, sets up yarn project, logs in, and tries to add a package.
#!/bin/bash
set -exuo pipefail
UNIQUE_STRING=$(date '+%Y%m%d-%H%M%S')
PROJECT=/tmp/yarn3-auth-repro-$UNIQUE_STRING
# Step 1: Create a new project in /tmp
mkdir -p $PROJECT
cd $_
yarn init -2
echo '
unsafeHttpWhitelist:
- localhost
npmRegistryServer: "http://localhost:8081/repository/npm-all"
npmAlwaysAuth: true
' >>.yarnrc.yml
# Step 2: Set up Nexus
NEXUS_CONTAINER=nexus-repro-container-$UNIQUE_STRING
docker run --rm --detach -p 8081:8081 --name $NEXUS_CONTAINER sonatype/nexus3@sha256:66fe12b1eb3e97bae72eb3c2c4e436499d41ff144cdfd1dcd0718df738304732
function cleanup {
read -p "Stop Nexus docker container $NEXUS_CONTAINER? (y/n) " STOP_CONTAINER
if [[ $STOP_CONTAINER == y* ]]; then
docker stop $NEXUS_CONTAINER
else
echo "You can play around in the project by going to the following directory:"
echo " cd $PROJECT"
echo "To stop the Nexus container, run:"
echo " docker stop $NEXUS_CONTAINER"
fi
}
trap cleanup EXIT
while ! docker logs $NEXUS_CONTAINER | grep 'Started Sonatype Nexus OSS' ; do echo "Waiting for $NEXUS_CONTAINER to start..."; sleep 2; done
printf '\a'
NEXUS_USER=admin
NEXUS_PASS="$(docker exec $NEXUS_CONTAINER cat /nexus-data/admin.password)"
# # Change admin password
# curl --fail --verbose -u "$NEXUS_USER:$NEXUS_PASS" 'http://localhost:8081/service/rest/internal/ui/onboarding/change-admin-password' -X PUT --data-raw 'admin123'
# sleep 1
# NEXUS_PASS=admin123
# Disallow anonymous access
curl --fail --verbose -u "$NEXUS_USER:$NEXUS_PASS" 'http://localhost:8081/service/extdirect' -X POST -H 'Content-Type: application/json' --data-raw '{"action":"coreui_AnonymousSettings","method":"update","data":[{"enabled":false,"userId":"anonymous","realmName":"NexusAuthorizingRealm"}],"type":"rpc","tid":14}'
# Create npm repo proxy
curl --fail --verbose -u "$NEXUS_USER:$NEXUS_PASS" 'http://localhost:8081/service/extdirect' -X POST -H 'Content-Type: application/json' --data-raw '{"action":"coreui_Repository","method":"create","data":[{"attributes":{"npm":{"removeNonCataloged":false,"removeQuarantinedVersions":false},"proxy":{"remoteUrl":"https://registry.npmjs.org","contentMaxAge":1440,"metadataMaxAge":1440},"httpclient":{"blocked":false,"autoBlock":true,"connection":{"useTrustStore":false}},"storage":{"blobStoreName":"default","strictContentTypeValidation":true},"negativeCache":{"enabled":true,"timeToLive":1440},"cleanup":{"policyName":[]}},"name":"npm-proxy","format":"","type":"","url":"","online":true,"routingRuleId":"","authEnabled":false,"httpRequestSettings":false,"recipe":"npm-proxy"}],"type":"rpc","tid":31}'
# Create npm repo group (which is my real setup)
curl --fail --verbose -u "$NEXUS_USER:$NEXUS_PASS" 'http://localhost:8081/service/extdirect' -X POST -H 'Content-Type: application/json' --data-raw '{"action":"coreui_Repository","method":"create","data":[{"attributes":{"storage":{"blobStoreName":"default","strictContentTypeValidation":true},"group":{"memberNames":["npm-proxy"]}},"name":"npm-all","format":"","type":"","url":"","online":true,"recipe":"npm-group"}],"type":"rpc","tid":44}'
# Make NPM login work <https://issues.sonatype.org/browse/NEXUS-20170>
curl --fail --verbose -u "$NEXUS_USER:$NEXUS_PASS" 'http://localhost:8081/service/extdirect' -X POST -H 'Content-Type: application/json' --data-raw '{"action":"coreui_RealmSettings","method":"update","data":[{"realms":["NexusAuthenticatingRealm","NexusAuthorizingRealm","NpmToken"]}],"type":"rpc","tid":43}'
# Step 3: Login
(echo "$NEXUS_USER"; sleep 2; echo "$NEXUS_PASS") | yarn npm login
yarn npm whoami
# Step 4: Add any random package to make sure auth works (this will fail)
yarn add mkdirp@latest
If you run this script and don’t shut down Nexus at the end (you will be asked if you want to), you can cd to the directory the script created, and manually add the token from $HOME/.yarnrc.yml to $PROJECT/.yarnrc.yml, like so:
unsafeHttpWhitelist:
- localhost
npmRegistryServer: "http://localhost:8081/repository/npm-all"
npmAlwaysAuth: true
npmRegistries:
"http://localhost:8081/repository/npm-all":
npmAlwaysAuth: true
npmAuthToken: NpmToken.xxxxxxxxxxxxx
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 27
- Comments: 25 (2 by maintainers)
Ok, so this seems to look like something attempted to be solved by the deep merge PR from #2106 which was rejected due to major breaking changes?
This is a bug, confirmed. The only way I can (so far) get
yarn configto appear properly andyarn addto work properly is to include my token in the project’syarnrc.yml(huge security hole) and specify my auth with BOTH thenpmRegistrieskey ANDnpmScopes.e.g.
^^^ this works as a project
yarnrc.ymlbut is unusable from a security perspective.well this is problematic and commenters don’t quite grok what’s happening so hopefully this explanation clears it up:
if you have a npmScopes: your-company: block in your ~/.yarnrc.yml, any keys there will be completely ignored (not merged) if there’s also a npmScopes: your-company: block on your project’s .yarnrc.yml. Therefore, whatever you try to use inside the npmScopes: your-company: block in ~/.yarnrc.yml won’t work at all. It will only work if there’s no npmScopes: your-company: block in your project’s .yarnrc.yml
yarn 4 fixes this no merging issue and will apply the project’s .yarnrc.yml over ~/.yarnrc.yml but keeping the values of keys that are specified in ~/.yarnrc.yml but not in the project’s .yarnrc.yml. so if you have a npmAlwaysAuth: true for the your-company scope on ~/.yarnrc.yml and not in the project’s .yarnrc.yml where you have other keys for the your-company scope, on yarn 4 it will respect the npmAlwaysAuth from ~/.yarnrc.yml, while on yarn 3 it will be false as it is the default and it ignores the your-company scope block from your home’s .yarnrc.yml because no merging.
hope this helps anyone and hope yarn 4 comes out soon officially.
It doesn’t ignore the token, it just doesn’t support configuration merging. In other words, the
npmRegistriesyou declare in your project yarnrc overrides the one in the global one (same fornpmScopes).That’s something we’ll fix in the next major, since it’s a breaking change, but it’s quite tricky to implement in a satisfying way, so it hasn’t been started yet.
Given the lack of reactions to this issue, I’ve added a Bash script to the original post which reproduces the error, using a local Nexus running in Docker. Enjoy!
It’ll not be backported to 3.x considering it’s a breaking change, and very difficult to cherry pick anyway. If you need it, please use the RCs.
I found a solution in another issue. It is required to specify the token inside
npmRegistriesfield. So your~/.yarnrc.ymlshould look like:Not sure if both are required, but the first one certainly is.
Wow, so the reason it works for people who use scopes is that it can take
npmScopesfrom project.yarnrc.ymlandnpmRegistriesfrom home dir.yarnrc.yml. This way it is possible to separate scopes/registries configuration from tokens.I don’t see a workaround for people who don’t use scopes.
@arcanis IMHO the only practical reason for separating the config is auth tokens, so perhaps that could simplify the solution i.e. it doesn’t really need to be general.
@arcanis I see. I eagerly await 4.0 then!
I figured it out. I needed to add
npmPublishRegistry: "https://registry.npmjs.org"to~/.yarnrc.yml.Can someone please summarize what has to go in
project/.yarnrc.ymland~/.yarnrc.ymlin version 3.x to publish without including the authentication tokens as part of the project?I tried the following and it did not work:
project/.yarnrc.yml:
~/.yarnrc.yml
I still get
YN0033: No authentication configured for requestwhen I runyarn npm publish --access=publicit doesn’t work for me with scoped packages on yarn 3.2.3 @__@
having a .yarnrc.yml like this:
I still get
➤ YN0041: │ @pkgscope/package-name@npm:^0.1.0: Invalid authentication (as an anonymous user)on yarn add@arcanis Is there an issue for the configuration merging that can be tracked? Or should I create one? It is quite a roadblock for us and we are very keen to get this feature in.
@alamothe this issue is called “yarn 3 ignores npmAuthTokens in ~/.yarnrc.yml” 😃 Running
yarn npm loginadds the token to~/.yarnrc.yml, so that’s not a problem; the problem is that yarn doesn’t use the token from~/.yarnrc.yml´ when I runyarn install`.Don’t know if adding
npmScopeschanges anything, but we don’t use scopes so that’s an academic question. We use a Nexus server which both acts as proxy for the public NPM repo and serves our own private packages, no scopes involved, auth always required.I am transitioning our projects to v3, and I have found the failure in authentication to the github package repo.
As you can see, I can publish a private package, but
yarn npm whoamireports no auth whereasnpm whoamireports myrosskevinuser.I investigated this path because previous packages published on https://npm.pkg.github.com/ are reporting unavailable with misleading messages such as:
whereas
npmworks fine:TL;DR yarn 3 authentication is not working with older github artifacts, and
yarn npm whoamiis misreportingNo authentication configured for requesteven thoughyarn npm publishsuccessfully publishes to the github repository!(as an aside, I tried publishing a current @alienfast/eslint-config with
yarn npm publishwhich is also successful but no yarn command can pull from that repo, even though npm can).SO … WHY can I publish but not install from the same config?