Appearance
NuGet Feed Setup
Section: 16 — Packages
Last Updated: 2026-05-30
Scope: Configure the Azure DevOps private NuGet feed for local development and CI/CD
Overview
All Microtec packages are published to a private Azure Artifacts feed hosted in Azure DevOps. Every developer machine and every CI/CD pipeline must authenticate to this feed before running dotnet restore or dotnet build.
Feed URL
https://pkgs.dev.azure.com/microtec/_packaging/Microtec/nuget/v3/index.json
Local Development Setup
Step 1 — Generate a Personal Access Token (PAT)
- Open Azure DevOps →
https://dev.azure.com/microtec - Click your profile avatar (top right) → Personal Access Tokens
- Click + New Token
| Field | Value |
|---|---|
| Name | nuget-local-{your-alias} |
| Organization | microtec |
| Expiration | 90 days (maximum recommended) |
| Scope | Packaging → Read |
- Copy the generated token — it is shown only once.
PAT Expiry
Set a calendar reminder 2 weeks before expiry. An expired PAT causes 401 Unauthorized during dotnet restore with no clear error message beyond the feed URL.
Step 2 — Add the NuGet Source
Run the following command, replacing <YOUR_PAT> with the token you just created:
bash
dotnet nuget add source \
"https://pkgs.dev.azure.com/microtec/_packaging/Microtec/nuget/v3/index.json" \
--name "Microtec" \
--username "any" \
--password "<YOUR_PAT>" \
--store-password-in-clear-text--store-password-in-clear-text
This flag is required on Linux and macOS because the .NET credential store on those platforms does not support encrypted credential storage in the same way Windows does. The PAT is stored in ~/.nuget/NuGet/NuGet.Config.
Step 3 — Verify the Source
bash
dotnet nuget list sourceExpected output includes:
Enabled
-------
3. Microtec [Enabled]
https://pkgs.dev.azure.com/microtec/_packaging/Microtec/nuget/v3/index.jsonStep 4 — Test Restore
bash
cd Platforms
dotnet restore Microtec.Platforms.slnA successful restore shows packages being downloaded from the Microtec source. No errors about missing packages.
Project-Level nuget.config
The Platforms/ directory contains a nuget.config file committed to source control. This file declares the feed so that developers do not need to memorise the URL — they only need to supply credentials.
xml
<!-- Platforms/nuget.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="Microtec"
value="https://pkgs.dev.azure.com/microtec/_packaging/Microtec/nuget/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="Microtec">
<package pattern="Microtec.*" />
</packageSource>
</packageSourceMapping>
</configuration>The <packageSourceMapping> block ensures Microtec.* packages are always resolved from the private feed only, and all other packages come from nuget.org. This prevents accidental dependency confusion attacks.
CI/CD Authentication (Azure DevOps Pipelines)
Pipelines use the built-in $(System.AccessToken) — no PAT management required.
Pipeline nuget.config injection
The build template injects credentials at runtime using the NuGetAuthenticate task:
yaml
steps:
- task: NuGetAuthenticate@1
displayName: Authenticate NuGet feed
- script: dotnet restore Microtec.Platforms.sln
displayName: Restore packagesNuGetAuthenticate@1 automatically populates $(System.AccessToken) as the credential for all sources declared in the project's nuget.config. You do not need to hardcode any tokens in pipeline YAML.
Docker builds — secret mount
Dockerfiles use --mount=type=secret to pass the PAT without baking it into the image:
dockerfile
RUN --mount=type=secret,id=nuget_pat \
NUGET_PAT=$(cat /run/secrets/nuget_pat) \
dotnet restore "MyService.Apis/MyService.Apis.csproj" \
-s "https://pkgs.dev.azure.com/microtec/_packaging/Microtec/nuget/v3/index.json" \
--configfile /dev/null \
/p:NuGetFeedUsername=any \
/p:NuGetFeedPassword=${NUGET_PAT}The pipeline passes the secret:
yaml
- script: |
docker build \
--secret id=nuget_pat,env=SYSTEM_ACCESSTOKEN \
-t $(imageName) .
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)Never bake the PAT into the image
Do not use ARG NUGET_PAT + ENV NUGET_PAT in Dockerfiles — this stores the token in every image layer and in the Docker build cache. Always use --mount=type=secret.
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
Unable to load the service index for source | Wrong feed URL or no network | Verify the URL matches exactly; check VPN |
401 Unauthorized | PAT expired or wrong scope | Regenerate PAT with Packaging → Read scope |
Package 'Microtec.X' is not found | Feed not listed or package not published | Run dotnet nuget list source; verify feed is enabled |
Response status code does not indicate success: 403 | PAT has insufficient scope | Ensure Packaging → Read is ticked, not just Packaging |
| Build fails in Docker but not locally | Secret not mounted | Verify --secret id=nuget_pat,env=... in docker build command |
Rotating a PAT
- Generate a new PAT in Azure DevOps (keep the old one active during transition)
- Update your local source:bash
dotnet nuget update source "Microtec" \ --username "any" \ --password "<NEW_PAT>" \ --store-password-in-clear-text - If using pipeline variables, update the
NUGET_PATvariable in Azure DevOps Library - Revoke the old PAT
Related
- Package Catalog — what each package contains
- Dependency Hierarchy — which packages depend on which
- Runbook: Deploy New Service — Dockerfile + pipeline setup