From e68b97c4a04f4ad7e94b57e2f6fc1e7440f51b77 Mon Sep 17 00:00:00 2001 From: ump45nose Date: Mon, 5 Oct 2026 05:22:35 +0800 Subject: [PATCH 1/3] docs(npmrc): document that auth scope must match registry URI exactly The auth keys `_authToken`, `_auth`, etc. are looked up by registry URI with an exact string match, but nothing in the docs said so. A scope that differs from the registry URL by a single trailing slash or a port is simply a different key, so npm finds no credentials at all and commands that need to log in fail with ENEEDAUTH and the generic "This command requires you to be logged in" message - the same message shown when no credentials were ever configured. Add a subsection to the auth configuration section explaining the exact-match rule, that a host-level scope is not a fallback for a path on that host, and that the ENEEDAUTH message is misleading in this case because the token is present but keyed to a non-matching URI. It also documents how to check which key npm actually resolved with `npm config get` and `npm config ls -l`. Closes: https://github.com/npm/cli/issues/3618 --- docs/lib/content/configuring-npm/npmrc.md | 42 +++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/docs/lib/content/configuring-npm/npmrc.md b/docs/lib/content/configuring-npm/npmrc.md index b1e7d16be10c7..6d6204cb3bfc7 100644 --- a/docs/lib/content/configuring-npm/npmrc.md +++ b/docs/lib/content/configuring-npm/npmrc.md @@ -105,6 +105,48 @@ If the credential is meant for any request to a registry on a single host, the s If it must be scoped to a specific path on the host that path may also be provided, such as `//my-custom-registry.org/unique/path:`. +#### The scope must match the registry URI exactly + +npm looks credentials up by the registry URI, and that lookup is an exact string match. +The scope in front of `_authToken` therefore has to be the same URI as `registry` (or a +`@scope:registry`) character for character, including any trailing slash. A host-level +scope does *not* act as a fallback for a request to a path on that host: if the registry +URL is `https://acme.com/api/v4/projects/123/packages/npm/`, then `//acme.com/:_authToken` +and `//acme.com/api/v4/projects/123/packages/npm:_authToken` (missing the final slash) are +both different keys and neither will be used. + +The scope and the registry URL are independent settings, so a typo in either one can break +authentication on its own. When they disagree, npm reports no credentials at all rather +than a partially matching token, and commands that need to log in fail with +`ENEEDAUTH` and the message "This command requires you to be logged in". That message is +the same one you get when no credentials have ever been configured, so it is misleading +in this case: the token is present, it is just keyed to a URI that does not match the +registry being written to. Check both settings before running `npm adduser`. + +To see which key npm actually resolved, ask for it by the registry URI: + +```bash +npm config get //acme.com/api/v4/projects/123/packages/npm/:_authToken +``` + +An empty result means no credential is keyed to that exact URI. `npm config ls -l` prints +the full list of keys as npm parsed them, which is the quickest way to spot a missing +slash or a different port. + +```ini +; the registry and the credential key disagree, so nothing is sent +@acme:registry=https://acme.com/projects/123/packages/npm/ +//acme.com/projects/123/packages/npm:_authToken=TOKEN + +; both URIs are identical, including the trailing slash +@acme:registry=https://acme.com/projects/123/packages/npm/ +//acme.com/projects/123/packages/npm/:_authToken=TOKEN +``` + +Note that the port is part of the key. A registry URL and a credential scope built from +different hostnames, or one built with `${CI_API_V4_URL}` and the other with +`${CI_REGISTRY}`, will not match even though both reach the same server. + ### Unsupported Custom Configuration Keys Starting in npm v11.2.0, npm warns when unknown configuration keys are defined in `.npmrc`. In a future major version of npm, these unknown keys may no longer be accepted. From 7dbf0e1c15a608dc29db5d752e25dfafa63d7a7f Mon Sep 17 00:00:00 2001 From: ump45nose Date: Sat, 10 Oct 2026 17:19:06 +0800 Subject: [PATCH 2/3] docs(npmrc): describe how credentials are matched to the registry URL --- docs/lib/content/configuring-npm/npmrc.md | 62 ++++++++--------------- 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/docs/lib/content/configuring-npm/npmrc.md b/docs/lib/content/configuring-npm/npmrc.md index 6d6204cb3bfc7..29a8d50c712c7 100644 --- a/docs/lib/content/configuring-npm/npmrc.md +++ b/docs/lib/content/configuring-npm/npmrc.md @@ -105,47 +105,27 @@ If the credential is meant for any request to a registry on a single host, the s If it must be scoped to a specific path on the host that path may also be provided, such as `//my-custom-registry.org/unique/path:`. -#### The scope must match the registry URI exactly - -npm looks credentials up by the registry URI, and that lookup is an exact string match. -The scope in front of `_authToken` therefore has to be the same URI as `registry` (or a -`@scope:registry`) character for character, including any trailing slash. A host-level -scope does *not* act as a fallback for a request to a path on that host: if the registry -URL is `https://acme.com/api/v4/projects/123/packages/npm/`, then `//acme.com/:_authToken` -and `//acme.com/api/v4/projects/123/packages/npm:_authToken` (missing the final slash) are -both different keys and neither will be used. - -The scope and the registry URL are independent settings, so a typo in either one can break -authentication on its own. When they disagree, npm reports no credentials at all rather -than a partially matching token, and commands that need to log in fail with -`ENEEDAUTH` and the message "This command requires you to be logged in". That message is -the same one you get when no credentials have ever been configured, so it is misleading -in this case: the token is present, it is just keyed to a URI that does not match the -registry being written to. Check both settings before running `npm adduser`. - -To see which key npm actually resolved, ask for it by the registry URI: - -```bash -npm config get //acme.com/api/v4/projects/123/packages/npm/:_authToken -``` - -An empty result means no credential is keyed to that exact URI. `npm config ls -l` prints -the full list of keys as npm parsed them, which is the quickest way to spot a missing -slash or a different port. - -```ini -; the registry and the credential key disagree, so nothing is sent -@acme:registry=https://acme.com/projects/123/packages/npm/ -//acme.com/projects/123/packages/npm:_authToken=TOKEN - -; both URIs are identical, including the trailing slash -@acme:registry=https://acme.com/projects/123/packages/npm/ -//acme.com/projects/123/packages/npm/:_authToken=TOKEN -``` - -Note that the port is part of the key. A registry URL and a credential scope built from -different hostnames, or one built with `${CI_API_V4_URL}` and the other with -`${CI_REGISTRY}`, will not match even though both reach the same server. +#### How npm matches a credential to a registry + +npm looks credentials up from the registry URL it is about to use (the `registry` +setting, or the matching `@scope:registry`). It starts from `//[:]` +and walks up the path one segment (or trailing slash) at a time until it finds a key +with credentials, stopping at `//[:]`. So for the registry +`https://acme.com/api/v4/projects/123/packages/npm/`, a credential keyed to +`//acme.com/api/v4/projects/123/packages/npm/:_authToken`, to a shorter path on the +same host, or to `//acme.com/:_authToken` is used, and the longest match wins. + +The host, including the port, has to match. A credential keyed to a different +hostname or port than the registry URL, for example one built from +`${CI_REGISTRY}` while the registry is built from `${CI_API_V4_URL}`, is never sent, +even if both names reach the same server. A path that is not a prefix of the +registry path does not match either. + +When no credential matches, commands that need to log in fail with `ENEEDAUTH` and a +"This command requires you to be logged in" message. That is the same error you get +when no credentials are configured at all, so if you have set a token and still see +it, compare the credential key with the registry URL. `npm config ls -l` prints every +key as npm parsed it. ### Unsupported Custom Configuration Keys From 2bdb2d65ff6cee6cbddaa039956472d0d4d0f7f0 Mon Sep 17 00:00:00 2001 From: ump45nose <52391318+ump45nose@users.noreply.github.com> Date: Fri, 23 Oct 2026 09:48:58 +0800 Subject: [PATCH 3/3] docs: use one sentence per line in added prose Apply the Markdown conventions from #10108 to this PR's new text only. Preserve wording, links, paragraph boundaries, and Markdown structure. Validation: rendered HTML equivalence (whitespace-normalized), text and scope assertions, and whitespace checks. Full npm/docs tests not run locally. AI-assisted formatting update. --- docs/lib/content/configuring-npm/npmrc.md | 30 +++++++++-------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/docs/lib/content/configuring-npm/npmrc.md b/docs/lib/content/configuring-npm/npmrc.md index 29a8d50c712c7..d4ca728c88867 100644 --- a/docs/lib/content/configuring-npm/npmrc.md +++ b/docs/lib/content/configuring-npm/npmrc.md @@ -107,25 +107,17 @@ If it must be scoped to a specific path on the host that path may also be provid #### How npm matches a credential to a registry -npm looks credentials up from the registry URL it is about to use (the `registry` -setting, or the matching `@scope:registry`). It starts from `//[:]` -and walks up the path one segment (or trailing slash) at a time until it finds a key -with credentials, stopping at `//[:]`. So for the registry -`https://acme.com/api/v4/projects/123/packages/npm/`, a credential keyed to -`//acme.com/api/v4/projects/123/packages/npm/:_authToken`, to a shorter path on the -same host, or to `//acme.com/:_authToken` is used, and the longest match wins. - -The host, including the port, has to match. A credential keyed to a different -hostname or port than the registry URL, for example one built from -`${CI_REGISTRY}` while the registry is built from `${CI_API_V4_URL}`, is never sent, -even if both names reach the same server. A path that is not a prefix of the -registry path does not match either. - -When no credential matches, commands that need to log in fail with `ENEEDAUTH` and a -"This command requires you to be logged in" message. That is the same error you get -when no credentials are configured at all, so if you have set a token and still see -it, compare the credential key with the registry URL. `npm config ls -l` prints every -key as npm parsed it. +npm looks credentials up from the registry URL it is about to use (the `registry` setting, or the matching `@scope:registry`). +It starts from `//[:]` and walks up the path one segment (or trailing slash) at a time until it finds a key with credentials, stopping at `//[:]`. +So for the registry `https://acme.com/api/v4/projects/123/packages/npm/`, a credential keyed to `//acme.com/api/v4/projects/123/packages/npm/:_authToken`, to a shorter path on the same host, or to `//acme.com/:_authToken` is used, and the longest match wins. + +The host, including the port, has to match. +A credential keyed to a different hostname or port than the registry URL, for example one built from `${CI_REGISTRY}` while the registry is built from `${CI_API_V4_URL}`, is never sent, even if both names reach the same server. +A path that is not a prefix of the registry path does not match either. + +When no credential matches, commands that need to log in fail with `ENEEDAUTH` and a "This command requires you to be logged in" message. +That is the same error you get when no credentials are configured at all, so if you have set a token and still see it, compare the credential key with the registry URL. +`npm config ls -l` prints every key as npm parsed it. ### Unsupported Custom Configuration Keys