Authenticated Feeds and Credential Providers
|
This section documents MSBuild 18.9, the .NET SDK 10.0.402 (with its This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The C# Reference bibliography lists the reference material consulted while preparing these pages. |
Private feeds — Azure Artifacts, GitHub Packages, AWS CodeArtifact, a self-hosted BaGetter or ProGet — usually require
credentials to read as well as to push. NuGet first sends an anonymous request and, on HTTP 401, looks for credentials
in a fixed order. This page walks that order against a BaGetter 1.6.5 instance on localhost:5556 configured for basic
authentication, with NuGet 7.9.0 (.NET SDK 10.0.402). No real token or host appears; the password used was a random
value held in an environment variable. Hosting such a feed is covered on
Private Feeds.
|
Never commit a token or password in |
Without credentials
<configuration>
<packageSources>
<clear />
<add key="ledger-private" value="http://localhost:5556/v3/index.json" allowInsecureConnections="true" />
</packageSources>
</configuration>
~/authfeed/C.csproj : error NU1301: Failed to retrieve information about 'Ledgerline' from remote source 'http://localhost:5556/v3/package/ledgerline/index.json'.
~/authfeed/C.csproj : error NU1301: Response status code does not indicate success: 401 (Unauthorized).
Pushing fails the same way, before the API key is even used — push first reads the service index:
error: Unable to load the service index for source http://localhost:5556/v3/index.json.
error: Response status code does not indicate success: 401 (Unauthorized).
1. An environment variable
NuGet first looks for NuGetPackageSourceCredentials_<source name> with the value
Username=<user>;Password=<secret> (optionally ;ValidAuthenticationTypes=basic):
env NuGetPackageSourceCredentials_ledger-private="Username=reader;Password=$FEED_PASSWORD" dotnet restore
env NuGetPackageSourceCredentials_ledger-private="Username=reader;Password=$FEED_PASSWORD" \
dotnet nuget push Ledgerline.1.0.0.nupkg -s ledger-private -k "$BAGETTER_API_KEY"
Restored ~/authfeed/C.csproj (in 663 ms).
PUT http://localhost:5556/api/v2/package/
Created http://localhost:5556/api/v2/package/ 691ms
Your package was pushed.
The name is the source’s key — here ledger-private, with a dash. A POSIX shell cannot export such a name
(export NuGetPackageSourceCredentials_ledger-private=… failed with exit code 1), so the variable was passed with
env; CI systems that set variables directly do not have that limitation, but a source key without dashes avoids the
problem. NuGet ignores a malformed variable silently and logs nothing about which credential it used.
Source: Credentials in environment variables.
2. packageSourceCredentials in nuget.config
<packageSourceCredentials>
<ledger-private>
<add key="Username" value="reader" />
<add key="ClearTextPassword" value="%LEDGER_FEED_PASSWORD%" />
</ledger-private>
</packageSourceCredentials>
With LEDGER_FEED_PASSWORD set the restore succeeded (Restored ~/authfeed/C.csproj (in 242 ms)); with it unset,
%LEDGER_FEED_PASSWORD% was sent literally and the restore failed with the same 401. The element name is the source
key (characters invalid in XML names are encoded). Password instead of ClearTextPassword holds a value encrypted
with dotnet nuget update source --password … — Windows only, and decryptable only by the same user on the same
machine, so not usable in a committed file.
The section does not have to be written by hand. With the macro quoted so that the shell passes it unchanged,
dotnet nuget add source wrote exactly the credentials above:
dotnet nuget add source http://localhost:5556/v3/index.json --name ledger-private \
--username reader --password '%LEDGER_FEED_PASSWORD%' --store-password-in-clear-text \
--allow-insecure-connections --configfile nuget.config
Package source with Name: ledger-private added successfully.
<packageSourceCredentials>
<ledger-private>
<add key="Username" value="reader" />
<add key="ClearTextPassword" value="%LEDGER_FEED_PASSWORD%" />
</ledger-private>
</packageSourceCredentials>
The nuget.exe equivalent (not run here; nuget.exe’s sources command takes the same values as -Name, -Source,
-UserName, -Password and -StorePasswordInClearText, plus -AllowInsecureConnections (nuget.exe 6.12+) for this
HTTP source; without -StorePasswordInClearText the password is stored encrypted, which again works only on Windows):
nuget sources add -Name ledger-private -Source http://localhost:5556/v3/index.json -UserName reader -Password "%LEDGER_FEED_PASSWORD%" -StorePasswordInClearText -AllowInsecureConnections -ConfigFile nuget.config
In cmd.exe a defined %LEDGER_FEED_PASSWORD% is expanded before nuget.exe sees it, which would write the secret
itself into the file; write the macro by hand in that case.
A trap while testing: right after a successful authenticated restore, a restore without credentials also
succeeded, because the HTTP cache answered for 30 minutes. Test authentication with an empty global-packages folder
and --no-http-cache.
3. Credential providers
A credential provider is a plugin that obtains a token itself — from a developer’s interactive sign-in, a managed
identity, or the CI system — so no secret is stored in configuration. The .NET SDK and MSBuild use the
cross-platform plugin protocol (V2); nuget.exe also supports the older V1 providers, and Visual Studio has its own
interface and ships the Azure Artifacts provider for itself (not for the dotnet CLI).
-
Discovery — by convention under
~/.nuget/plugins/netcore/<name>/<name>.dll(andnetfxfor .NET Framework hosts), or from paths inNUGET_PLUGIN_PATHS(NUGET_NETCORE_PLUGIN_PATHSfor thedotnetCLI only). From NuGet 6.13 (SDK 9.0.200) NuGet also searchesPATHfor executables namednuget-plugin-*, which is how a provider installed as a .NET (global) tool is found. -
Known providers — the Azure Artifacts Credential Provider (
microsoft/artifacts-credprovider, also installed by theNuGetAuthenticate@1pipeline task), the AWS CodeArtifact provider, and MyGet’s for Visual Studio. GitHub Packages has none; use a personal access token through one of the first two methods. -
Interactive or not — a provider may need a browser or device-code sign-in.
dotnet restore --interactive(or-p:NuGetInteractive=truefor MSBuild) allows it to prompt; without the flag, as in CI, it must obtain a token silently or fail.
Which method where
| Situation | Use |
|---|---|
Developer machine, Azure Artifacts or CodeArtifact |
The credential provider, |
CI |
The CI’s secret store, exposed as |
Personal feeds with tokens (GitHub Packages) |
A token in the user-level |
The documentation ranks them: credential provider first, then encrypted credentials (Windows), then %VARIABLE%
macros, then raw environment variables, and clear-text values last.
Common mistakes
-
Testing credentials with a warm HTTP cache — success that proves nothing.
-
An unset
%VARIABLE%— sent literally; 401. -
Source keys with dashes and
export— the variable is never set. -
Expecting Visual Studio’s Azure Artifacts provider to work for
dotnet— install the CLI provider separately. -
Credentials in the repository’s
nuget.config— see the warning above.