@@ -58,14 +58,21 @@ export async function publish(args) {
5858 logger . info ( `Package: ${ packageJson . name } @${ packageJson . version } ` ) ;
5959 logger . info ( `Build time: ${ buildTime } ` ) ;
6060 logger . info ( `Short SHA: ${ shortSha } ` ) ;
61- logger . info ( `Token: '${ obfuscateToken ( args . accessToken ) } '` ) ;
61+ if ( args . useOidc ) {
62+ logger . info ( `Authentication: OIDC (Trusted Publishing)` ) ;
63+ } else {
64+ logger . info ( `Token: '${ obfuscateToken ( args . accessToken ) } '` ) ;
65+ }
6266 logger . info ( `Repository: ${ repoUrl } ` ) ;
6367 logger . info ( `Last commit message: ${ commitMessage } ` ) ;
6468 logger . info ( `Last commit author: ${ commitAuthorWithEmail } ` ) ;
6569 logger . info ( `Registry: ${ args . registry || 'https://registry.npmjs.org/' } ` ) ;
6670
67- if ( ! args . accessToken ?. length ) {
68- logger . warn ( `No access token provided. Publishing to registry ${ args . registry } may fail.` ) ;
71+ if ( ! args . useOidc && ! args . accessToken ?. length ) {
72+ logger . warn ( `No access token provided and OIDC not enabled. Publishing to registry ${ args . registry } may fail.` ) ;
73+ }
74+ if ( args . useOidc ) {
75+ logger . info ( `OIDC authentication enabled. Ensure your CI/CD has id-token: write permissions and a trusted publisher is configured on npmjs.com.` ) ;
6976 }
7077
7178 // Remove slahes from the end of the tag (this may happen if the tag is provided by github ref_name
@@ -126,7 +133,7 @@ export async function publish(args) {
126133 msg += `Commit URL: ${ repoUrl } /commit/${ shortSha } \n` ;
127134 msg += `Build time: ${ buildTime } \n` ;
128135 msg += `Registry: ${ args . registry } \n` ;
129- msg += `Token : ${ obfuscateToken ( args . accessToken ) } \n` ;
136+ msg += `Auth : ${ args . useOidc ? 'OIDC (Trusted Publishing)' : obfuscateToken ( args . accessToken ) } \n` ;
130137 msg += `Tag: ${ args . tag || '-' } ${ args . useTagInVersion ? ' (version+tag)' : '' } ${ args . createGitTag ? ' (creating git tag)' : '' } \n` ;
131138 msg += "```" ;
132139 await sendMessageToWebhook ( webhook , msg , { logger } ) ;
@@ -197,13 +204,13 @@ export async function publish(args) {
197204 // Default env
198205 const env = {
199206 ...process . env ,
200- NPM_TOKEN : args . accessToken || undefined ,
207+ NPM_TOKEN : args . useOidc ? undefined : ( args . accessToken || undefined ) ,
201208 NPM_CONFIG_REGISTRY : ( args . registry || 'https://registry.npmjs.org/' ) ,
202209 }
203210
204211
205212 // set config
206- {
213+ if ( ! args . useOidc ) {
207214 let registryUrlWithoutScheme = ( args . registry || 'https://registry.npmjs.org/' ) . replace ( / h t t p s ? : \/ \/ / , '' ) ;
208215 if ( ! registryUrlWithoutScheme . endsWith ( '/' ) ) registryUrlWithoutScheme += '/' ;
209216
@@ -223,6 +230,19 @@ export async function publish(args) {
223230 // env
224231 // });
225232 // }
233+ } else {
234+ logger . info ( `Skipping npm config auth token setup - using OIDC authentication` ) ;
235+ // Clear any existing auth tokens that might interfere with OIDC
236+ // npm OIDC works best when there's no conflicting token configuration
237+ let registryUrlWithoutScheme = ( args . registry || 'https://registry.npmjs.org/' ) . replace ( / h t t p s ? : \/ \/ / , '' ) ;
238+ if ( ! registryUrlWithoutScheme . endsWith ( '/' ) ) registryUrlWithoutScheme += '/' ;
239+ try {
240+ const clearCmd = `npm config delete //${ registryUrlWithoutScheme } :_authToken` ;
241+ logger . info ( `Clearing any existing auth token for OIDC: ${ clearCmd } ` ) ;
242+ tryExecSync ( clearCmd , { cwd : packageDirectory , env } ) ;
243+ } catch {
244+ // Ignore errors - token might not exist
245+ }
226246 }
227247
228248 const htmlUrl = args . registry ?. includes ( "npmjs" ) ? `https://www.npmjs.com/package/${ packageJson . name } /v/${ packageJson . version } ` : ( args . registry + `/${ packageJson . name } ` ) ;
@@ -257,7 +277,12 @@ export async function publish(args) {
257277 logger . info ( `Package view result ${ packageVersionPublished } ` ) ;
258278
259279
260- let cmd = `npm publish --access public`
280+ const registryUrl = args . registry || 'https://registry.npmjs.org/' ;
281+ let cmd = `npm publish --access public --registry ${ registryUrl } `
282+ if ( args . useOidc ) {
283+ cmd += ' --provenance' ;
284+ logger . info ( `OIDC authentication enabled, adding --provenance flag for trusted publishing.` ) ;
285+ }
261286 if ( dryRun ) {
262287 cmd += ' --dry-run' ;
263288 logger . info ( `Dry run mode enabled, not actually publishing package.` ) ;
@@ -294,8 +319,66 @@ export async function publish(args) {
294319 }
295320 else {
296321 logger . error ( `❌ Failed to publish package ${ packageJson . name } @${ packageJson . version } \n${ res . error } ` ) ;
322+
323+ // Provide helpful OIDC troubleshooting information if OIDC was enabled
324+ if ( args . useOidc ) {
325+ const errorStr = res . error ?. toString ( ) || res . output ?. toString ( ) || '' ;
326+ const is404Error = errorStr . includes ( '404' ) || errorStr . includes ( 'Not found' ) || errorStr . includes ( 'Not Found' ) ;
327+ const is401Error = errorStr . includes ( '401' ) || errorStr . includes ( 'Unauthorized' ) ;
328+ const is403Error = errorStr . includes ( '403' ) || errorStr . includes ( 'Forbidden' ) ;
329+
330+ logger . error ( `\n${ '=' . repeat ( 80 ) } ` ) ;
331+ logger . error ( `OIDC TROUBLESHOOTING GUIDE` ) ;
332+ logger . error ( `${ '=' . repeat ( 80 ) } ` ) ;
333+
334+ if ( is404Error ) {
335+ logger . error ( `\n⚠️ ERROR: 404 Not Found` ) ;
336+ logger . error ( ` This usually means one of the following:\n` ) ;
337+ logger . error ( ` a) FIRST-TIME PUBLISH: The package doesn't exist on npmjs.com yet.` ) ;
338+ logger . error ( ` → First publish MUST be done with a token: --access-token <token>` ) ;
339+ logger . error ( ` → After first publish, configure trusted publisher, then use --oidc\n` ) ;
340+ logger . error ( ` b) TRUSTED PUBLISHER NOT CONFIGURED for this package.` ) ;
341+ logger . error ( ` → Go to: https://www.npmjs.com/package/${ packageJson . name } /access` ) ;
342+ logger . error ( ` → Click "Settings" → "Trusted Publisher" → "GitHub Actions"` ) ;
343+ logger . error ( ` → Configure: organization/user, repository, workflow filename\n` ) ;
344+ logger . error ( ` c) WORKFLOW FILENAME MISMATCH` ) ;
345+ logger . error ( ` → The workflow filename on npmjs.com must EXACTLY match your .yml file` ) ;
346+ logger . error ( ` → Check for typos, case sensitivity, and path differences\n` ) ;
347+ } else if ( is401Error ) {
348+ logger . error ( `\n⚠️ ERROR: 401 Unauthorized` ) ;
349+ logger . error ( ` The OIDC token was not accepted. Check:\n` ) ;
350+ logger . error ( ` a) GitHub Actions must have 'id-token: write' permission` ) ;
351+ logger . error ( ` b) Trusted publisher must be configured on npmjs.com` ) ;
352+ logger . error ( ` c) npm version must be >= 11.5\n` ) ;
353+ } else if ( is403Error ) {
354+ logger . error ( `\n⚠️ ERROR: 403 Forbidden` ) ;
355+ logger . error ( ` Access denied. Check:\n` ) ;
356+ logger . error ( ` a) You have publish permissions for this package` ) ;
357+ logger . error ( ` b) Trusted publisher configuration matches your workflow exactly` ) ;
358+ logger . error ( ` c) Repository owner/name matches the trusted publisher config\n` ) ;
359+ } else {
360+ logger . error ( `\nOIDC authentication failed. Please check the following:\n` ) ;
361+ }
362+
363+ logger . error ( `CHECKLIST:` ) ;
364+ logger . error ( ` □ Package exists on npmjs.com (first publish requires --access-token)` ) ;
365+ logger . error ( ` □ Trusted publisher configured: https://www.npmjs.com/package/${ packageJson . name } /access` ) ;
366+ logger . error ( ` □ Workflow has 'id-token: write' permission` ) ;
367+ logger . error ( ` □ npm version >= 11.5 (current: run 'npm --version' to check)` ) ;
368+ logger . error ( ` □ Using cloud-hosted runner (not self-hosted)` ) ;
369+ logger . error ( ` □ Workflow filename matches exactly (case-sensitive)\n` ) ;
370+ logger . error ( `DOCUMENTATION:` ) ;
371+ logger . error ( ` → npm Trusted Publishing: https://docs.npmjs.com/trusted-publishers/` ) ;
372+ logger . error ( ` → npm Provenance: https://docs.npmjs.com/generating-provenance-statements/` ) ;
373+ logger . error ( `${ '=' . repeat ( 80 ) } \n` ) ;
374+ }
375+
297376 if ( webhook ) {
298- await sendMessageToWebhookWithCodeblock ( webhook , `❌ **Failed to publish package** \`${ packageJson . name } @${ packageJson . version } \`:` , res . error , { logger } ) ;
377+ let errorMsg = `❌ **Failed to publish package** \`${ packageJson . name } @${ packageJson . version } \`:` ;
378+ if ( args . useOidc ) {
379+ errorMsg += `\n⚠️ OIDC was enabled. See logs for troubleshooting guide or visit: https://docs.npmjs.com/trusted-publishers/` ;
380+ }
381+ await sendMessageToWebhookWithCodeblock ( webhook , errorMsg , res . error , { logger } ) ;
299382 }
300383 throw new Error ( `Failed to publish package ${ packageJson . name } @${ packageJson . version } : ${ res . error } ` ) ;
301384 }
0 commit comments