Skip to content

Conversation

@pwoosam
Copy link

@pwoosam pwoosam commented Dec 17, 2025

This RFC proposes the implementation of a credential provider plugin protocol for the NPM CLI to enable secure, dynamic retrieval of authentication tokens. The protocol will allow external credential providers to supply short-lived tokens at runtime, eliminating the need to store secrets in plaintext within .npmrc files or environment variables.

@pwoosam pwoosam requested a review from a team as a code owner December 17, 2025 19:47

## Unresolved Questions and Bikeshedding

- How will credential providers be registered? (e.g. bundled with npm-cli, well-known globally installed node_module, well-known and dynamically installed by npm-cli, etc.).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems pretty important to be configurable both per-project and also globally; additionally, pretty critical that anybody be able to be a credential provider with no action taken by npm.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update this to allow project-level and user-level configuration. Noted that credential providers should be able to be provided without any action taken by NPM.

## Unresolved Questions and Bikeshedding

- How will credential providers be registered? (e.g. bundled with npm-cli, well-known globally installed node_module, well-known and dynamically installed by npm-cli, etc.).
- Can custom credential providers be registered via a new setting in `.npmrc`?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most all npm config can be set up with env vars and npmrc, so this seems like a "yes"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.npmrc will have a configuration to register credential providers then. This is something that pnpm has implemented: https://pnpm.io/settings#urltokenhelper

However, pnpm's implementation has limitations that are not desirable:

The configuration for the path to the helper must be an absolute path, with no arguments. In order to be secure, it is only permitted to set this value in the user .npmrc. Otherwise a project could place a value in a project's local .npmrc and run arbitrary executables.

Setting a token helper for the default registry:

tokenHelper=/home/ivan/token-generator

Setting a token helper for the specified registry:

//registry.corp.com:tokenHelper=/home/ivan/token-generator

The registry context isn't passed to the Credential Provider in pnpm's case, which is a challenge for generating credentials scoped to the registry. Ideally, the registry uri would be sent to the provider for context. Otherwise, a wrapper script would need to be created to supply the context, which is not a great solution.

- Can custom credential providers be registered via a new setting in `.npmrc`?
- What is the expected output format (e.g., JSON, plain text)?
- How should errors be surfaced to the user?
- Should NPM CLI support caching of tokens returned by the provider or is this the provider's responsibility?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

presumably, like cookies, the provider should be able to provide a lifetime that the client obeys?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the NPM cli will expect the credential provider to supply an expiresAt timestamp and npm cli will provide in-memory caching for the duration of the current NPM operation (it will call the provider again if the current timestamp is near the expiration)

@wraithgar
Copy link
Member

It seems to me that before any of the items under "bikeshedding" are discussed we need to figure out

Defining the protocol for provider invocation.

Without this, this RFC is just a very high level wish. What, exactly, is a "credential provider" here? Is it oauth? Is it just another layer of auth? Is it, like OIDC, another trust layer?

Where is the security/trust model in this approach? One of the concerns folks have had w/ OIDC is that it simply moves trust to another domain. How is this different? Put another way how do I authenticate with a credential provider? Is that authentication model secure? Are we just moving the bubble under tape here or does this provide a real improvement against current models?

If it helps we can identify specifically the problems this solves, be honest about the ones it doesn't solve, and go from there.

From what I see this is intended to solve the "Bearer token authentication has to have the bearer token stored somewhere" problem. If the bearer token can never live anywhere outside of runtime memory in npm itself then why not implement a "prompt for login/2fa to get a bearer token directly from the npm registry" workflow? Can this be solved by having an npm cli mode where it is never logged in, and makes you log in on invocation?

As far as what this does not solve, this will likely have the same shortcomings as something like OIDC. Unless this credential provider is exclusively an npm registry feature it is equivalent to outsourcing the trust model to a third party.

Finally, is there prior art in the Node.js ecosystem? If this does not exist yet it represents quite a significant development and maintenance burden. Who will own this?

@pwoosam
Copy link
Author

pwoosam commented Dec 19, 2025

What, exactly, is a "credential provider" here? Is it oauth? Is it just another layer of auth? Is it, like OIDC, another trust layer?

A Credential Provider is an interface to acquire a token for authenticating with an NPM registry. It is not a new auth protocol, likely the Credential Provider uses OAuth/OIDC under the hood or whatever the registry requires.

The Credential Provider is an integration mechanism between the NPM CLI and an authentication helper.

Where is the security/trust model in this approach?

There are some new trust boundaries in this approach:

  • NPM -> Credential Provider selection and execution
    • 1st party Credential Provider should be selected first (npmjs.com, github packages, etc.)
    • 3rd party Credential Provider must be sandboxed and not have access to NPM memory
    • NPM must constrain which Credential Providers can be executed
      • Allowlist of credential providers (well-known node_modules/binaries?)
      • User-level config (~/.npmrc)
      • Project-level config (./.npmrc)
  • Credential Provider -> Identity Provider (Entra, GitLab, AWS, other SSO, etc.)
    • This is managed by the Credential Provider
    • Ideally token storage is ephemeral or encrypted in OS-level secret storage, but ultimately this is up to the Credential Provider.
  • NPM -> Registry (existing boundary)
    • NPM will send auth token to registry. The auth token will be provided by a Credential Provider.

Put another way how do I authenticate with a credential provider?

NPM executes the provider for a registry uri (e.g. artifacts-npm-credprovider -registry-uri <uri>), then the provider performs interactive auth and returns { token, expiresAt } via stdout (well-defined and structured output). NPM then uses the token for the operation in-memory, then discards it.

Is that authentication model secure?

Security depends on the Credential Provider's implementation and token handling. NPM cli should restrict the execution of arbitrary executables without consent from the user. The big improvement is removing plaintext token persistence from developer machines, encouraging shorter token lifetimes, and encouraging secure enterprise-grade auth flows implemented by credential providers.

For npmjs.com itself, perhaps NPM would ship its own credential provider that would behave similarly to npm login --registry=<uri> for npmjs and github packages registry URIs.

If it helps we can identify specifically the problems this solves, be honest about the ones it doesn't solve, and go from there.

We are solving:

  • plaintext token removal
  • shifting storage responsibility, encouraging ephemeral storage and shorter token lifetime
  • Access token lifecycle management

We are not solving:

  • Registry auth model shortcomings (scopes, token audience, MFA, etc.)
  • Credential Provider-side storage/security if the provider is poorly implemented

If the bearer token can never live anywhere outside of runtime memory in npm itself then...?

I'm not saying that a token can never live anywhere outside of runtime memory for NPM. But it cannot live in plaintext or in environment variables. Token storage should be ephemeral or locked in encrypted OS-level storage like Windows Credential Manager or MacOS Keychain Access. I'm proposing that from NPM's should treat tokens ephemerally and the choice between ephemeral or secure storage is up to the Credential Provider.

why not implement a "prompt for login/2fa to get a bearer token directly from the npm registry" workflow?

The prompt login would solve the problem for npmjs.com registry, but not for 3rd party registries like:

  • Azure Artifacts
  • GitLab
  • GitHub Packages
  • AWS CodeArtifact
  • Google Artifact Registry
  • JFrog Artifactory
  • etc.

Unless this credential provider is exclusively an npm registry feature it is equivalent to outsourcing the trust model to a third party.

I think this is accurate. This is essentially a feature for NPM registries. For NPM-owned registries (npmjs and github packages) NPM can ship/maintain the provider.

For external registries, the enterprise should ship their own provider. And NPM should enforce guardrails to avoid using 3rd party providers for 1st party registries, require used consent for project-level and user-level configs, and potentially an allowlist for certain providers.

Prior Art from Node.js ecosystem

Who will own this?

  • NPM will own the NPM-owned registry Credential Providers (NPM + GitHub)
  • NPM will own the NPM cli hook and configuration implementation for calling 3rd party credential providers
  • 3rd parties will own their Credential Providers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants