Skip to content

feat(release): publish to npm without a token, via OIDC - #123

Merged
navbytes merged 1 commit into
mainfrom
npm-trusted-publishing
Aug 23, 2026
Merged

feat(release): publish to npm without a token, via OIDC#123
navbytes merged 1 commit into
mainfrom
npm-trusted-publishing

Conversation

@navbytes

Copy link
Copy Markdown
Owner

Summary

@navbytes/vee now publishes through npm trusted publishing. The registry
verifies this workflow's OIDC identity instead of a stored credential, so there
is no NPM_TOKEN to leak, to rotate, or to forget.

Configured on the package: publisher GitHub Actions, repository
navbytes/vee, workflow release.yml, permission npm publish.
Nothing else can publish it.

Why, beyond tidiness

v0.3.0 failed to publish twice, both times because of how npm treats tokens:

  1. A granular token without 2FA bypass is rejected outright — npm error code EOTP: This operation requires a one-time password. No CI can answer
    that.
  2. A token with bypass has its publishes staged for manual confirmation.
    That is why the job reported + @navbytes/vee@0.3.0 while the registry
    returned {"error":"Not found"} — the package existed with zero versions.

npm is restricting bypass tokens for direct publishing regardless (it warns
about it in the publish output), so the token path was on its way out. OIDC
sidesteps all of it.

It also removes a 90-day expiry. npm caps write tokens there with no "never
expires" option, so the token was guaranteed to lapse and take a future release
with it — the same shape as the Homebrew tap sitting two releases stale.

Changes

  • NODE_AUTH_TOKEN and the missing-token guard are gone; there is no credential
    to check for.
  • --provenance dropped — attestation is automatic under OIDC. Verified the
    0.3.0 publish already carries a SLSA provenance predicate.
  • id-token: write unchanged; it is what OIDC needs.
  • The already-published guard stays, so a re-run still skips a version that is
    live rather than failing on it.

Requirements met

npm trusted publishing needs npm >= 11.5.1. Node 24 ships npm 11.17, and the
job already pins node-version: 24.

Follow-ups, deliberately not in this PR

  1. Delete NPM_TOKEN after a release proves OIDC works. Left in place for
    now so there is a fallback if something is misconfigured.
  2. Tighten "Publishing access" on the package to "Require two-factor
    authentication and disallow bypass 2fa tokens"
    . npm notes trusted publishers
    keep working under any setting and recommends the most restrictive one — but
    sequencing matters: prove OIDC first, then remove the other door.

Type of change

  • New feature (non-breaking change that adds functionality)

Testing done

  • release.yml validated as YAML; no NPM_TOKEN reference remains.
  • Confirmed @navbytes/vee@0.3.0 is live, installs, and all three builders work
    from the published package.
  • Confirmed the published version already carries a provenance attestation.

The publish path itself is only exercised by a real release — that is the next
one.

https://claude.ai/code/session_0159CBiPNW97Nnn9oDyk7VyP

@navbytes/vee now publishes through npm trusted publishing: the registry
verifies this workflow's OIDC identity rather than a stored credential. The
package is configured to trust navbytes/vee's release.yml and nothing else.

This removes a credential that had to be created, stored, and rotated every 90
days — npm caps write tokens there, with no "never expires" option — and whose
lapse would have surfaced as a failed release next quarter.

It also removes the failure mode that broke 0.3.0's first attempt twice over. A
granular token without 2FA bypass is rejected outright (EOTP), which no CI can
answer. A token *with* bypass gets its publishes staged for manual confirmation
instead of going live, which is why 0.3.0 reported a successful publish while
the registry returned "Not found". npm is restricting bypass tokens for direct
publishing anyway, so the token path was on its way out regardless.

Provenance is attested automatically under OIDC, so the explicit --provenance
flag is gone. id-token: write is still required and already granted.

NPM_TOKEN is deliberately left in the repository secrets until a release proves
OIDC works; it is unused from this commit on and should be deleted after that.

Claude-Session: https://claude.ai/code/session_0159CBiPNW97Nnn9oDyk7VyP
@navbytes
navbytes force-pushed the npm-trusted-publishing branch from 89a0caf to c4048a0 Compare August 23, 2026 16:00
@navbytes
navbytes merged commit 5b5158a into main Aug 23, 2026
10 checks passed
@navbytes
navbytes deleted the npm-trusted-publishing branch August 23, 2026 16:00
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