gh-npm-auth-preinstall
v0.4.0
Published
Save yourself from 403s when installing private GitHub Packages. Pass one or more @scopes; the tool checks whether your gh auth can read them and walks you through fixing it if not.
Maintainers
Readme
gh-npm-auth-preinstall
Save yourself from 403 Forbidden when installing private GitHub Packages.
Pass one or more @scope arguments. The tool probes api.github.com with
your current ~/.npmrc token and tells you whether you can read packages
from those scopes. If you can't, it walks you through fixing it via the
gh CLI and writes the refreshed token to
~/.npmrc.
Works on macOS, Linux, and Windows. Node 18+. See Platform support for specifics.
Install
Run it ad-hoc:
npx gh-npm-auth-preinstall @your-org
pnpm dlx gh-npm-auth-preinstall @your-org @another-orgOr add it to a project as a dev dependency + preinstall hook:
pnpm add -D gh-npm-auth-preinstall// package.json
{
"scripts": {
"preinstall": "gh-npm-auth-preinstall @your-org || true"
}
}The || true keeps the very first install from failing before the
binary is on disk. After that, the check runs on every install.
CLI
gh-npm-auth-preinstall @scope [@scope ...]
-h, --help Show help
-v, --version Print version
-n, --dry-run Detect problems but don't run gh or write ~/.npmrc
-f, --force Run even on CI / when GH_NPM_AUTH_SKIP is setScopes are positional. The leading @ is optional —
gh-npm-auth-preinstall traild and gh-npm-auth-preinstall @traild are
equivalent. Pass as many as you need. Duplicates and case differences
are deduped.
If no scopes are passed, the tool prints a warning and exits 0 — it
never errors on missing arguments.
What it does
- Reads your auth token from
~/.npmrc(line//npm.pkg.github.com/:_authToken=...), expanding${ENV}references. - For each scope, sends
GET https://api.github.com/orgs/<scope>/packages?package_type=npmwith the token. Falls back to/users/<scope>/packagesif 404.200→ access works.401→ token missing or invalid.403→ token lacksread:packagesscope or SSO is required for the org.
- If anything fails: checks that
ghis installed, runsgh auth loginorgh auth refresh --scopes read:packages, grabs the new token viagh auth token, and upserts the//npm.pkg.github.com/:_authTokenline in~/.npmrc. - Re-probes. If 403s persist, prints SSO authorization guidance with the exact org URLs to authorize.
Independently of the auth flow, the tool also ensures ~/.npmrc
contains node-options=--use-system-ca. npm and pnpm read that config
and prepend it to NODE_OPTIONS for the install process and its
lifecycle scripts, so subsequent installs trust the OS certificate
store (Windows cert store, macOS Keychain, Linux ca-certificates). This
matters behind corporate TLS-inspecting proxies. The option is appended
to any existing node-options= line; if --use-system-ca is already
present, the file is left alone. Requires Node 22.15+ / 23+ for
--use-system-ca to take effect.
If gh isn't installed, prints platform-specific install instructions
and exits non-zero.
CI / non-interactive environments
The tool auto-skips on CI. If CI=true (set by every major CI
provider — GitHub Actions, GitLab, CircleCI, Travis, Vercel, Netlify,
Buildkite, etc.), the tool exits 0 immediately with a one-line log and
doesn't probe the registry. CI builds don't pay the network cost and
don't break on first-run.
In CI, set up auth the normal way:
@your-org:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}Manual control
| Knob | Effect |
| -------------------------- | ----------------------------------------------------- |
| CI=true | Auto-skips (default behaviour on every CI provider). |
| GH_NPM_AUTH_SKIP=1 | Force skip anywhere — local, CI, sandbox, anywhere. |
| --force / -f | Run even when CI is detected or GH_NPM_AUTH_SKIP is set. Useful for testing the CI bailout. |
| CI=false or CI=0 | Treated as "not CI" — the tool runs normally. |
Platform support
| Platform | Status | Notes |
| --- | --- | --- |
| macOS | ✅ Tested | Primary dev target. brew install gh for the CLI. |
| Linux | ✅ Works | Identical code path to macOS. apt / dnf / pacman instructions printed when gh is missing. |
| Windows | ✅ Works | Resolves gh.exe on Windows (Node's spawn doesn't search PATHEXT, so this is explicit). Uses os.homedir() → C:\Users\<name>\.npmrc. winget / scoop / choco instructions printed when gh is missing. chmod 0o600 on ~/.npmrc is a best-effort no-op on Windows. |
Terminal notes for Windows
ANSI colors render correctly in Windows Terminal, PowerShell 5+, and cmd.exe on Windows 10+. Older terminals (legacy cmd.exe pre-Win10 Anniversary) may show escape codes as garbage; set NO_COLOR=1 to disable colors.
Shell quirks
The CLI never invokes anything via a shell (spawn is called with shell: false), so spaces in paths, quoting, and shell metacharacters in tokens are all safe across platforms.
SSO orgs
If your org enforces SAML SSO, a personal access token (even with
read:packages) won't work until you authorize it for the org. After
running the tool, if you still see 403, the tool prints the exact SSO
authorization URL for each affected org. Open it, click Authorize,
and re-run.
Why not just npm login?
npm login --registry=https://npm.pkg.github.com works, but:
- it doesn't tell you whether your token has the wrong scopes,
- it doesn't help with SSO authorization,
- it doesn't say which scopes you can or can't read,
- it stores credentials in a way that surprises some pnpm setups.
This tool gives a focused, fast diagnostic + fix, then gets out of the way.
Development
pnpm install
pnpm build # produces dist/index.js with a node shebang
pnpm typecheck
node ./dist/index.js --helpTests
Tests use Node's built-in node:test runner via tsx (no Jest/Vitest).
pnpm test # build + run full suite
pnpm test:unit # parser, token, upsert, scope normalization — no network
pnpm test:cli # spawn-based CLI tests (some hit api.github.com)
pnpm test:offline # full suite with network tests skippedNetwork tests verify the probe correctly classifies 401 from
api.github.com for invalid tokens. Set GH_NPM_AUTH_OFFLINE=1 to
skip them in airgapped environments.
License
MIT
