[BUG] Claude Code Proxy Issue: Private NPM Package Authentication Failure
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code Proxy Issue: Private NPM Package Authentication Failure
Date: 2025-11-05 Environment: Claude Code on the Web Issue: Cannot authenticate with GitHub Packages npm registry for private packages Status: Blocking development workflow
The Claude Code proxy's scoped credential system successfully injects GitHub authentication for git operations but does not provide the necessary read:packages scope for accessing private npm packages from GitHub Packages registry. Additionally, when users attempt to provide their own authentication token via .npmrc, the proxy strips the Authorization header, preventing any workaround.
Impact: Users cannot install private npm packages from GitHub Packages, blocking dependency installation for projects that rely on private organizational packages.
What Should Happen?
Executive Summary
The Claude Code proxy's scoped credential system successfully injects GitHub authentication for git operations but does not provide the necessary read:packages scope for accessing private npm packages from GitHub Packages registry. Additionally, when users attempt to provide their own authentication token via .npmrc, the proxy strips the Authorization header, preventing any workaround.
Impact: Users cannot install private npm packages from GitHub Packages, blocking dependency installation for projects that rely on private organizational packages.
Technical Details
Environment
- Platform: Claude Code on the Web
- Proxy: Claude Code HTTPS security proxy (as documented)
- Registry:
npm.pkg.github.com(GitHub Packages npm registry) - Package Type: Private scoped npm packages (
@organization/package-name) - Authentication Method Attempted: Personal Access Token (classic) with
read:packagesscope
The Problem
Claude Code's proxy implements a scoped credential system that automatically injects GitHub authentication for *.github.com domains. However:
- The injected credential lacks
read:packagesscope needed for GitHub Packages npm registry - User-provided authentication tokens are stripped by the proxy
- No documented workaround exists for private package registry authentication
Error Messages/Logs
Steps to Reproduce
Reproduction Steps
Setup
-
Create a private npm package published to GitHub Packages:
- Organization:
<your-org> - Package:
@<your-org>/<package-name> - Version:
1.0.0-<hash> - Published to:
https://npm.pkg.github.com/<your-org>
- Organization:
-
Create repository with read access:
- Repository:
<your-org>/<your-repo> - Grant repository read access to the package in GitHub Packages settings
- Repository:
-
Create Personal Access Token (classic):
- Scope:
read:packages - Verify it works locally on developer machine
- Scope:
Test Case 1: Using .npmrc with Authentication Token
Configuration:
# .npmrc in project root
registry=https://npm.pkg.github.com/<your-org>
//npm.pkg.github.com/:_authToken=ghp_[40-character-token]
Command:
npm install @<your-org>/<package-name>@<version>
Expected Result: Package installs successfully (this works on local machine with identical configuration)
Actual Result:
npm error code E401
npm error Unable to authenticate, your authentication token seems to be invalid.
Evidence:
17 http fetch GET 401 https://npm.pkg.github.com/<your-org>/@<your-org>%2f<package-name> 26ms (cache skip)
23 verbose stack HttpErrorAuthUnknown: Unable to authenticate, need: Bearer realm="", error="invalid_token"
Analysis:
- Error code 401 Unauthorized means no authentication was received by GitHub
- The same
.npmrcand token work perfectly on local machine - Verbose curl output shows proxy strips the Authorization header:
(Header is empty - token was stripped)* [HTTP/2] [1] [authorization: token ]
Test Case 2: Relying on Proxy Auto-Injected Credentials
Configuration:
# .npmrc without authentication token
registry=https://npm.pkg.github.com/<your-org>
Command:
npm install @<your-org>/<package-name>@<version>
Expected Result: Proxy injects GitHub authentication with sufficient scope to access packages
Actual Result:
npm error code E403
npm error 403 403 Forbidden - GET https://npm.pkg.github.com/<your-org>/@<your-org>%2f<package-name>
npm error 403 Permission denied
Analysis:
- Error code 403 Forbidden (not 401) proves authentication IS being sent
- The proxy successfully injects its scoped credential
- But the credential lacks the
read:packagesscope needed for private packages - This matches the documented behavior: "scoped credential" works for git, but not for package registries
Test Case 3: Direct curl Access
Command:
curl -H "Authorization: Bearer $GITHUB_TOKEN" \
"https://npm.pkg.github.com/@<your-org>/<package-name>"
Result:
{"error":"unauthenticated: User cannot be authenticated with the token provided."}
Analysis:
- Same 401 error as npm
- Confirms the proxy strips Authorization headers for
npm.pkg.github.com - The proxy's scoped credential injection doesn't apply to curl (or doesn't have proper scope)
Evidence Summary
| Test Scenario | Auth Method | HTTP Status | Error Message | Interpretation |
|---|---|---|---|---|
With user token in .npmrc |
User-provided PAT | 401 | "invalid_token" | Proxy strips auth header |
Without auth in .npmrc |
Proxy-injected | 403 | "Permission denied" | Proxy token lacks read:packages |
Same .npmrc on local machine |
User-provided PAT | 200 | Success | Proves token and config are valid |
| curl with Bearer token | User-provided PAT | 401 | "unauthenticated" | Confirms header stripping |
Claude Model
Other
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
Claude Code Web
Platform
Other
Operating System
Other
Terminal/Shell
Other
Additional Information
Root Cause Analysis
Based on Claude Code documentation and observed behavior:
From Documentation
"the git client uses a scoped credential inside the sandbox, which the proxy verifies and translates to your actual GitHub authentication token"
This scoped credential system:
- ✅ Works for git operations (clone, fetch, push to current branch)
- ❌ Does not extend to npm registry authentication
- ❌ Lacks
read:packagesscope even if it did apply
From Observed Behavior
- Proxy intercepts all HTTPS traffic to
npm.pkg.github.com - Proxy strips user-provided Authorization headers (security feature)
- Proxy injects its own scoped credential for GitHub domains
- Scoped credential has insufficient permissions for private package access
Business Impact
Affected Use Cases
- Private organizational npm packages - Cannot access internal design systems, shared libraries, or proprietary components
- Monorepo development - Cannot install workspace dependencies published to GitHub Packages
- Enterprise workflows - Organizations using GitHub Packages for internal distribution are blocked
- Third-party private packages - Cannot consume private packages from vendors using GitHub Packages
Current Workarounds
Workaround 1: Manual tarball distribution
# Developer downloads locally
npm pack @organization/package@version
# Manually provides .tgz file to Claude Code session
npm install ./package.tgz
- ❌ Breaks automated workflows
- ❌ Requires manual intervention for every package update
- ❌ Not scalable for multiple dependencies
Workaround 2: Make packages public
- ❌ Not acceptable for proprietary code
- ❌ Security and compliance concerns
- ❌ Defeats purpose of private packages
Workaround 3: Use alternative registries
- ❌ Forces architecture changes
- ❌ Requires migrating packages
- ❌ May not be feasible for existing projects
Proposed Solutions
Solution 1: Extend Scoped Credential Scope (Recommended)
Description:
Extend the proxy's auto-injected GitHub token to include read:packages scope.
Implementation:
- When proxy detects requests to
npm.pkg.github.com - Inject GitHub token with both git and package registry scopes
- Similar to how git credentials are currently handled
Pros:
- ✅ Seamless user experience
- ✅ No configuration required
- ✅ Consistent with existing git authentication pattern
- ✅ Works for all GitHub Packages registries (npm, maven, nuget, etc.)
Cons:
- Requires infrastructure changes to proxy
- May need user consent for expanded scope
Solution 2: Allow User-Provided Registry Authentication
Description: Configure proxy to preserve Authorization headers for package registry domains.
Implementation:
- Add
npm.pkg.github.comto allowlist for passthrough auth - Preserve Authorization headers for recognized package registries
- Users provide tokens via
.npmrcas standard practice
Pros:
- ✅ Standard npm authentication pattern
- ✅ Users control token scopes
- ✅ Works with existing workflows
- ✅ Supports all package registries (npm, PyPI, etc.)
Cons:
- May conflict with proxy security model
- Requires careful allowlist management
Solution 3: Registry-Specific Proxy Translation
Description: Implement credential translation specifically for package registries.
Implementation:
- Similar to git credential translation
- Detect package registry requests (
npm.pkg.github.com,pypi.org, etc.) - Translate user session credentials to appropriate registry auth
Pros:
- ✅ Maintains proxy security model
- ✅ Extensible to other registries
- ✅ User-transparent authentication
Cons:
- Most complex to implement
- Requires per-registry integration
Solution 4: Documentation and Configuration Guide
Description: If technical limitation prevents proxy-level fix, provide clear documentation.
Implementation:
- Document the limitation in Claude Code docs
- Provide detailed workaround instructions
- Add troubleshooting section for package registry auth
Pros:
- ✅ Immediate availability
- ✅ Sets correct user expectations
Cons:
- ❌ Doesn't solve the underlying problem
- ❌ Still blocks workflows
Recommended Action
Priority: High - This blocks a common enterprise development pattern
Suggested Approach:
- Short-term: Document the limitation and workarounds (Solution 4)
- Medium-term: Implement Solution 2 (passthrough auth for registries)
- Long-term: Implement Solution 1 (extend scoped credentials)
Additional Context
Related Documentation
- Claude Code Network Access: https://docs.claude.com/en/docs/claude-code/claude-code-on-the-web#network-access-and-security
- Scoped Credential System: Mentioned in proxy documentation
Related Issues
- Similar to how the proxy handles git authentication successfully
- May affect other package managers (pip, cargo, maven, nuget) accessing private registries
- GitHub issue reference: Users report
.npmrcsetup before claude-code-action as workaround- This suggests workflow-level configuration might work
- But doesn't solve the core proxy authentication issue
Verification Steps for Anthropic Engineering
To reproduce this issue:
- Create a private npm package in any GitHub organization
- Publish to GitHub Packages npm registry
- Create a repository and grant it package read access
- In Claude Code session:
- Create
.npmrcwith proper authentication - Attempt
npm install @org/package@version - Observe 401 error
- Create
- Remove authentication from
.npmrc:- Keep only
registry=https://npm.pkg.github.com/org - Attempt
npm installagain - Observe 403 error (proving auth is injected but lacks scope)
- Keep only
- Test same configuration locally:
- Use identical
.npmrcwith authentication - Observe successful installation
- Use identical
This demonstrates:
- User token + config are valid (works locally)
- Proxy strips user auth (401 with token, 403 without)
- Proxy injects credential (403 vs 401) but insufficient scope
Date: 2025-11-05
This issue is blocking active development and would benefit from Anthropic engineering review.
I'm running into this a lot... I've managed to work around almost every other CCW issue, but this one is beyond my ability to work around.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
Experiencing the same issue and it's a major blocker. Surprisingly, it works with bun install (if executed in the "Full" network mode), but not with yarn or npm, probably since bun doesn't use the http proxy inside the container.