Skip to content

ci: publish to npm via trusted publishing (OIDC), not a 2FA-bypass token - #11

Merged
sinameraji merged 1 commit into
mainfrom
ci/npm-trusted-publishing
Aug 10, 2026
Merged

ci: publish to npm via trusted publishing (OIDC), not a 2FA-bypass token#11
sinameraji merged 1 commit into
mainfrom
ci/npm-trusted-publishing

Conversation

@sinameraji

Copy link
Copy Markdown
Owner

⚠️ Do not merge until step 1 below is done

Merging this before the trusted publisher is registered on npmjs.com will break the next release publish — the workflow will have no token and no registered publisher.

The problem

The publish job authenticated with secrets.NPM_TOKEN. npm automation tokens bypass 2FA by design — that is what they are for. So the account's strongest protection did not cover the single most sensitive operation in the repo: shipping code to everyone who runs npm i -g gitflare. Anyone holding that token publishes a release on their own, with no second factor in the way.

This is also on a clock: bypass-2FA tokens stop working for publishing in January 2027, when npm moves publishing to OIDC.

The fix

Trusted publishing removes the standing credential entirely. GitHub mints a short-lived OIDC credential scoped to one workflow run; npm verifies it against a publisher registered for this repo and this exact workflow filename. Nothing to exfiltrate, nothing to rotate, nothing that works outside a run of this workflow.

Workflow changes:

  • id-token: write on the publish job only — release-please doesn't need it.
  • Node 22 + npm install -g npm@latest in the publish job. OIDC needs Node >= 22.14 and npm >= 11.5.1, and Node 22 still bundles npm 10.x. ci.yml stays on Node 20 so the engines: >=20 floor is still tested.
  • NODE_AUTH_TOKEN dropped; the npm CLI detects the OIDC environment itself.

Side benefit: npm generates provenance attestations automatically for public packages published this way, so releases become cryptographically traceable back to this repo and commit.

Rollout — order matters

  1. Register the trusted publisher at npmjs.com → gitflare package → Settings → Trusted Publisher. GitHub Actions; org/user sinameraji; repository gitflare; workflow filename release-please.yml; no environment. All fields are case-sensitive and must match exactly.
  2. Merge this PR.
  3. Cut a release and confirm the publish job succeeds and the new version shows a provenance badge on npm.
  4. Then set npmjs.com → gitflare → Settings → Publishing access → "Require two-factor authentication and disallow tokens." Trusted publishing keeps working — that setting only blocks traditional token auth.
  5. Revoke the old credential: delete NPM_TOKEN from the repo's Actions secrets, and revoke the token itself at npmjs.com → Access Tokens.

Step 4 is what actually closes the hole; steps 1–3 just make sure releases still ship when it does. Step 5 makes it irreversible.

Caveat worth knowing

The trusted publisher pins the workflow filename. Renaming release-please.yml breaks publishing until the registration is updated — noted in a comment on the job.

🤖 Generated with Claude Code

The publish job authenticated with secrets.NPM_TOKEN. Automation tokens
bypass 2FA by design — that's their whole purpose — so the strongest
account protection did not cover the one operation that matters most:
shipping code to everyone who runs `npm i -g gitflare`. A leaked token
publishes a release on its own.

Trusted publishing removes the standing credential entirely. GitHub mints
a short-lived OIDC credential scoped to a single workflow run, and npm
verifies it against a publisher registered for this repo + this exact
workflow filename. Nothing to exfiltrate, nothing to rotate.

- id-token: write on the publish job only (release-please doesn't need it)
- Node 22 + npm@latest in the publish job: OIDC needs Node >= 22.14 and
  npm >= 11.5.1, and Node 22 still bundles npm 10.x. ci.yml stays on
  Node 20 so the engines >= 20 floor is still tested.
- NODE_AUTH_TOKEN dropped; the npm CLI detects OIDC on its own.

Side benefit: npm generates provenance attestations automatically for
public packages published this way, so releases become verifiable back to
this repo and commit.

REQUIRES a one-time setup on npmjs.com before this merges — see the PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sinameraji
sinameraji merged commit efcd591 into main Aug 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant