Skip to content

feat: switch npm publish to Trusted Publishing (OIDC), drop NPM_TOKEN - #4

Merged
ytspar merged 1 commit into
mainfrom
feat/oidc-trusted-publishing
Jul 10, 2026
Merged

feat: switch npm publish to Trusted Publishing (OIDC), drop NPM_TOKEN#4
ytspar merged 1 commit into
mainfrom
feat/oidc-trusted-publishing

Conversation

@ytspar

@ytspar ytspar commented Jul 10, 2026

Copy link
Copy Markdown
Owner

What

Switches the push-to-publish workflow from a stored npm token to npm Trusted Publishing (OIDC). No NPM_TOKEN secret at all — GitHub Actions mints a short-lived, workflow-scoped OIDC token (id-token: write, already granted) that npm exchanges for publish rights.

Why

You were right that classic Automation tokens no longer exist — npm retired them in the 2025 token overhaul. The token stored for #2 was a classic Publish token, which still enforces 2FA OTP in CI: the first main publish run got all the way through tests and provenance-signing, then failed with EOTP ("requires a one-time password"). Trusted Publishing is the modern replacement and is strictly better — nothing to store, rotate, or leak, and provenance stays automatic.

Changes

  • Remove the NPM_TOKEN requirement step and the NODE_AUTH_TOKEN env on publish.
  • Add an in-run npm install -g npm@latest — Trusted Publishing needs npm CLI ≥ 11.5.1 / Node ≥ 22.14, and Node 22's bundled npm is 10.x.
  • --provenance kept explicit (automatic for a public repo + package anyway).
  • README + workflow header document the one-time npmjs.com config.

One-time setup (package owner — replaces the token secret)

On npmjs.com, hardcode-replacer → Settings → Trusted Publisher → GitHub Actions:

  • Organization/user: ytspar
  • Repository: hardcode-replacer
  • Workflow filename: publish.yml
  • Environment: (leave blank)

Then merge this PR. The main run sees 2.3.0 ≠ registry (2.2.0) and performs the pending v2.3.0 publish with zero token. You can also delete the now-unused NPM_TOKEN secret and optionally enable "require 2FA and disallow tokens" on the package for defense in depth.

Testing

ci runs jest on this PR (ripgrep installed, per #3). The publish path only runs on main.

npm retired classic Automation tokens in the 2025 overhaul; the token
stored for #2 was a classic Publish token that still enforces 2FA OTP in
CI (the EOTP the first publish run hit). Trusted Publishing replaces the
token entirely: GitHub Actions OIDC (id-token: write, already granted)
mints a short-lived workflow-scoped token that npm exchanges for publish
rights — nothing to store, rotate, or leak.

Changes:
- Remove the NPM_TOKEN requirement step and NODE_AUTH_TOKEN env.
- Upgrade npm to >= 11.5.1 in-run (Node 22 ships npm 10.x; Trusted
  Publishing needs 11.5.1+ / Node 22.14+).
- Provenance stays automatic for a public repo+package; --provenance
  kept explicit.
- README + header document the one-time npmjs.com Trusted Publisher
  config (the only remaining human step, replacing the token secret).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ytspar

ytspar commented Jul 10, 2026

Copy link
Copy Markdown
Owner Author

AI review (advisory) — cycle 1

Advisory only. GitHub blocks author self-approval, so this closes at handoff (your merge).
Reviewed against: PR #4 HEAD (a5ca05c)

Summary

Correct migration from a stored token to npm Trusted Publishing (OIDC). Verified against npm's current docs: the mechanism needs exactly what this workflow provides — id-token: write (already granted), npm CLI ≥ 11.5.1 (added the in-run npm install -g npm@latest, since Node 22 ships npm 10.x), Node ≥ 22.14 (node-version: 22 resolves to 22.19+), and no token. Provenance is automatic for public repo+package; --provenance is kept as a harmless explicit request.

Findings

nit: registry-url on setup-node writes an .npmrc with a NODE_AUTH_TOKEN placeholder that OIDC doesn't use — harmless (the placeholder is simply unread when OIDC auth kicks in), keeps the registry pinned. No action.

No blockers. Prior workflow guards preserved: main-ref gate, whole-string name/version validation, version-change publish gate, ripgrep install (#3).

Verification

  • ci check green on this PR (jest + ripgrep).
  • YAML validates; publish.yml runs only on main/dispatch, so this PR doesn't attempt a publish.

Handoff — the one-time step this replaces the token with

On npmjs.com: hardcode-replacer → Settings → Trusted Publisher → GitHub Actions → org ytspar, repo hardcode-replacer, workflow publish.yml, no environment. Then merge → the main run publishes v2.3.0 tokenlessly. Afterward you can delete the unused NPM_TOKEN secret.

Verdict (a5ca05c): APPROVE (handoff — merge is yours)

@ytspar
ytspar merged commit b8860d7 into main Jul 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