Welcome to the Inedo Forums! Check out the Forums Guide for help getting started.
If you are experiencing any issues with the forum software, please visit the Contact Form on our website and let us know!
401 When trying to download assests from private repo
-
ProGet Version: 2025.x (latest Docker image as of January 2026)
Feed Types Affected: npm, PyPI
Issue Description:
ProGet connector forwards credentials for package metadata requests but does NOT forward credentials for file download requests, causing downloads to fail with HTTP 500 errors.
Pattern:
Metadata requests: HTTP 200 (credentials forwarded successfully)
File downloads: HTTP 500 "WebException" (credentials NOT forwarded, underlying 401 from upstream)
Test Case (npm):
Setup:
- Feed: npm
- Connector URL: https://libraries.cgr.dev/javascript/
- Authentication: Basic Auth
Command:
npm install debug --registry http://localhost/npm/feed-name/Results:
Metadata: GET /javascript/debug → HTTP 200 (success)
Tarball: GET /javascript/files/.../debug-4.4.3.tgz → HTTP 500 (failure)npm error: 500 Internal Server Error - WebException
Root Cause:
The upstream registry (Chainguard) uses content-addressable storage where files are at different paths than metadata:
- Metadata: https://libraries.cgr.dev/javascript/debug
- Files: https://libraries.cgr.dev/javascript/files/[hash]/debug-4.4.3.tgz
ProGet forwards credentials to the base URL but not to the /files/ sub-path.
Related Bugs:
This appears similar to Bug PG-1121 (fixed in 4.8.6), but the issue persists in ProGet 2025.x for npm and PyPI feeds.
Questions:
- Was PG-1121 fix applied to npm/PyPI feeds, or only NuGet?
- Is there a configuration option to forward credentials to all paths under the connector base URL?
- Is this a known limitation with content-addressable storage URLs?
-
Wanted to share the output from a client trying to install a package:
25 silly packumentCache corgi:http://localhost/npm/Chainguard/lodash cache-miss 26 http fetch GET 200 http://localhost/npm/Chainguard/lodash 765ms (cache miss) 27 silly packumentCache corgi:http://localhost/npm/Chainguard/lodash set size:6616 disposed:false 28 http fetch GET http://localhost/npm/Chainguard/lodash/-/lodash-4.17.20.tgz attempt 1 failed with 500 29 http fetch GET http://localhost/npm/Chainguard/lodash/-/lodash-4.17.20.tgz attempt 2 failed with 500 30 http fetch GET http://localhost/npm/Chainguard/lodash/-/lodash-4.17.20.tgz attempt 3 failed with 500 31 http fetch GET 500 http://localhost/npm/Chainguard/lodash/-/lodash-4.17.20.tgz 73187ms attempt #3 (cache skip) 32 verbose stack HttpErrorGeneral: 500 Internal Server Error - GET http://localhost/npm/Chainguard/lodash/-/lodash-4.17.20.tgz - WebException 32 verbose stack at C:\Program Files\nodejs\node_modules\npm\node_modules\npm-registry-fetch\lib\check-response.js:103:15 32 verbose stack at process.processTicksAndRejections (node:internal/process/task_queues:103:5) 33 verbose statusCode 500 34 verbose pkgid lodash@http://localhost/npm/Chainguard/lodash/-/lodash-4.17.20.tgz 35 error code E500 36 error 500 Internal Server Error - GET http://localhost/npm/Chainguard/lodash/-/lodash-4.17.20.tgz - WebException 37 silly unfinished npm timer reify 1768329298512 38 silly unfinished npm timer reify:unpack 1768329299498 39 silly unfinished npm timer reifyNode:node_modules/lodash 1768329299498We have this same behavior for both NPM and Python. This presents as a 401 in the WebUI but a 500 from a client.
-
Thanks for putting all the details together, this is really helpful! In theory, what you're doing should work... and I don't know why it's not. But it sounds like it'd be "trivial" to reproduce in a debug environment, so let's start there :)
All we really need are credentials. It looks like your end-user opened a ticket on this issue as well (EDO-12512), so I will just add your email to that ticket and respond there with the same request.
Once we have credentials, we'll try reproducing/fixing and hopefully get this working in no time :)
Cheers,
Alana
-
I was able to identify the issue.
When you visit the URL in ProGet, then ProGet will visit this URL (slightly trimmed) with the appropriate authorization header:
https://libraries.cgr.dev/javascript/..../lodash/-/lodash-4.17.20.tgzHowever, that URL will issue a 307 redirect to the following:
/artifacts-downloads/javascript/namespaces/15f7d141c3b76b85/repositories/.../downloads/ABmYrfCH......KpxO1ducu3xmMRtw==ProGet then follows the redirect, but does not send the authorization header. And thus, a
401is issued. This is actually the default/expected behavior inHttpClient(i.e. the library in .NET we use) and most clients in other languages (Java, Go, Ruby, etc.) as well.Of course it can be worked-around by disabling auto-redirect and implementing yourself to follow the URl with the same header. But that's not so common and, as such, it's not a common practice for servers to issue redirects that require authentication; we see other services handle the redirect using some kind of token in the querystring.
On our end, this has not been an issue to date. This is logic is buried pretty deep and it's not an easy fix without changing code everything relies on. I'm kind of surprised
npmandpipoverride the default behavior in thefetch()andrequestslibraries.Anyway, it sounds like you can make a change on the private repository server code... so I would here would be to just disable authentication on your
artifacts-downloadsendpoint. I mean that URL is basically authenticated anyway.... it's so long (I stripped like 1000 characters) that it's basically a password.Thanks,
Alana