Skip to content

Migrate npm-publish.yml to trusted publishing (OIDC), drop NPM_TOKEN #2016

Description

@alexwarren

Summary

npm-publish.yml currently authenticates to npm using a long-lived granular access token (NPM_TOKEN repo secret) with 2FA bypass. npm/GitHub are deprecating that bypass in two phases (see changelog):

  • Phase 1 (early August 2026, already in effect): 2FA-bypass tokens can no longer create/delete tokens, change account/password/email/2FA settings, change package access/maintainers/trusted-publishing config, or manage org/team membership.
  • Phase 2 (~January 2027): 2FA-bypass tokens lose direct publishing ability entirely — reduced to "reading private packages and staging a publish, where a package only becomes public after a human 2FA approval."

We already hit Phase 1 in practice: the very first CI publish of @textadventures/quest-viva-wasmplayer failed with npm error code EOTP because creating the package for the first time needed to establish maintainer/ownership (a Phase-1-restricted action even for a bypass-capable token). It was bootstrapped with a one-off manual npm publish from a local machine with real 2FA instead. Ordinary version-bump publishes from CI should be unaffected until Phase 2 lands, but Phase 2 will break them too.

What to do

Migrate npm-publish.yml to npm's trusted publishing (OIDC) instead of a long-lived token:

  1. On the package's npmjs.com settings page, add a Trusted Publisher: GitHub Actions, repo textadventures/quest, workflow file npm-publish.yml (no environment).
  2. Update .github/workflows/npm-publish.yml:
    • Add permissions: id-token: write (and contents: read) to the job.
    • Drop the NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} env var from the "Publish to npm" step — npm's CLI auto-detects the GitHub Actions OIDC environment once a trusted publisher is configured, no token needed.
  3. Once confirmed working on a real release, remove the now-unused NPM_TOKEN repo secret.

This sidesteps the whole 2FA-bypass-token question going forward and isn't affected by the Phase 2 deprecation.

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions