Skip to content
Latchkey

NuGet restore 403 (Forbidden) - Under-Scoped Feed Token in CI

Unlike a 401 (no/invalid credentials), a 403 means NuGet authenticated successfully but the identity is not allowed to read the feed. The token is valid but under-scoped, or the account lacks feed access.

What this error means

Restore fails on a private source with 403 (Forbidden) rather than 401. It is deterministic - the same job fails identically every run - and persists until the token gains read permission, distinguishing it from a transient 5xx.

dotnet restore output
error : Response status code does not indicate success: 403 (Forbidden).
error : Unable to load the service index for source
https://nuget.pkg.github.com/contoso/index.json.

Common causes

Token authenticated but lacks read scope

A PAT or app token valid for the org may not have the Packaging/read:packages scope the feed requires, so the feed accepts the identity but forbids the read.

Identity has no permission on the specific feed

The user or service account behind the token is not a member/reader of the feed (a private Azure Artifacts feed or a GitHub Packages repo it cannot see), producing 403 rather than 401.

How to fix it

Grant the token the read scope

Re-issue the token with the feed-read permission, then re-register the source.

Terminal
# GitHub Packages: token needs read:packages
dotnet nuget add source https://nuget.pkg.github.com/contoso/index.json \
  --name github --username USER \
  --password "$GH_PACKAGES_TOKEN" --store-password-in-clear-text

Confirm the identity can read the feed

  1. Verify the service account/user is a reader on the specific feed, not just the org.
  2. Check the token has not been scoped down to a different feed or resource.
  3. Re-run restore and confirm the 403 is gone before treating it as fixed.

How to prevent it

  • Scope feed tokens to least privilege but include the read permission the feed needs.
  • Grant the CI identity explicit reader access on each private feed.
  • Track token expiry/rotation so access does not silently lapse to a 401/403.

Frequently asked questions

What causes ""403 (Forbidden)" on restore"?
A PAT or app token valid for the org may not have the Packaging/read:packages scope the feed requires, so the feed accepts the identity but forbids the read.
How do I fix "403 (Forbidden)" on restore?
Re-issue the token with the feed-read permission, then re-register the source.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card