GitHub Actions npm 403: registry·OIDC·패키지 권한 구분

npm publish의 403을 보면 먼저 요청한 registry와 package scope를 확인합니다. npmjs.com의 OIDC trusted publishing과 GitHub Packages의 GITHUB_TOKEN은 같은 인증 경로가 아닙니다. permissions: write-all을 추가해 둘 다 해결하려는 방식은 원인을 분리하지 못합니다.

node --version
npm --version
npm config get registry
npm pkg get name version publishConfig

패키지 scope별 registry와 publishConfig가 기본 registry를 덮는지도 봅니다. .npmrc 전체나 토큰을 출력하지 마세요. ENEEDAUTH 역시 파일 인코딩 문제로 단정할 수 없으며, 어떤 registry에 어떤 인증 방식을 적용하려 했는지부터 확인해야 합니다.

npmjs.com OIDC 경로의 확인 조건

2026-09-21 확인한 npm trusted publishing 문서는 npm CLI 11.5.1 이상, Node 22.14.0 이상과 GitHub-hosted runner를 요구합니다. GitHub job의 id-token: write와 npm 패키지에 등록한 소유자·저장소·workflow 파일명·선택적 environment가 실제 실행과 맞아야 합니다. 같은 저장소의 다른 workflow에서 실행한 성공은 현재 workflow의 일치를 증명하지 않습니다.

GitHub Packages라면 확인할 권한이 바뀐다

GitHub npm registry 문서의 패키지 접근과 workflow 연결을 확인합니다. GITHUB_TOKEN으로 발행하는 job의 packages: write와 대상 패키지의 접근 관계를 대조해야 합니다. npmjs.com의 trusted publisher 등록이나 id-token 권한만으로 GitHub Packages 쓰기 권한을 얻는 것은 아닙니다.

검증 결과를 실제 발행 성공과 구분하기

버전·registry·인증 방식이 맞으면 기존 버전 재발행 여부와 패키지 소유 권한 등 실제 응답에 해당하는 조건을 좁힙니다. npm publish –dry-run은 배포 파일 검토에 유용하지만 OIDC 교환이나 실제 registry 쓰기 권한의 성공을 증명하지 않습니다. 일부 lifecycle script가 실행될 수 있으므로 검토한 저장소에서만 사용합니다.

최종 확인은 승인된 release job의 실제 결과와 의도한 registry에 나타난 패키지·버전으로 합니다. 이번 글에서는 패키지를 발행하거나 권한을 변경하지 않았습니다. 문서 조건을 확인한 결과를 실제 OIDC 발행 실험으로 표시하지 않습니다.