dotnet restore 403 (Forbidden) from a private feed in CI
A 403 means the token authenticated successfully but is not permitted to read this feed. Unlike a 401, retrying with the same token will not help; the token needs the right scope or membership.
What this error means
restore fails with "Response status code does not indicate success: 403 (Forbidden)" for the private source. The credentials are accepted but access to the feed is denied.
error NU1301: Unable to load the service index for source https://nuget.pkg.github.com/org/index.json.
Response status code does not indicate success: 403 (Forbidden).Common causes
The token lacks read scope for the feed
A GitHub token without read:packages, or an Azure PAT without Packaging read, authenticates but is forbidden from listing the feed.
The principal is not a member of the feed
The token belongs to a user or app that is not granted access to that specific feed or organization, so reads are refused.
How to fix it
Grant the token the right scope
- For GitHub Packages, use a token with
read:packages(orpackages: readin workflow permissions). - For Azure Artifacts, issue a PAT with Packaging (Read) scope.
- Confirm the token principal is a member of the feed, then re-run.
permissions:
packages: readVerify feed membership for a persistent 403
A 403 that survives token rotation means access, not credentials. Add the user, app, or service principal to the feed with read permission.
How to prevent it
- Scope restore tokens to Packaging/packages read only.
- Add the CI principal to the feed as part of onboarding a new repo.
- Distinguish 401 (no valid creds) from 403 (no access) when triaging.