cli icon indicating copy to clipboard operation
cli copied to clipboard

validating auth context when using OIDC to publish

Open travi opened this issue 4 months ago • 7 comments

hi, folks 👋🏼

i maintain semantic-release and have been working toward adding official support for using the newly available trusted publishing. making the actual trusted publish work was straight forward enough, but i've been running into some roadblocks enabling it in the context of the rest of what semantic-release tries to enable as part of the release process.

the primary complication is a result of the fact that semantic-release interacts with several systems as part of the release process and cannot make the full release atomic. because of that, we do our best to precheck that the various steps are expected to be successful before taking steps that cannot be undone. for npm, we attempt to ensure the available token will be able to publish successfully.

before trusted publishing, we did our best to check this with npm whoami. this fell short of proving that a token had privileges to publish, but does confirm that the token is valid and not typo'd. with trusted publishing npm whoami isnt available (and wouldnt make as much logical sense as named anyway).

it was suggested to me that i could try to use dry-run with npm publish to accomplish similar, which sounded great. thankfully i found the shortcoming of this approach before fully moving forward with it. what wasn't clear to me on the surface was that dry-run was providing valuable feedback about the presence of a token or oidc context, but does not validate that the token is actually valid according to the registry. this comment appears to confirm that this is intentional behavior, which unfortunately leaves me in a tough spot for semantic-release. a dry-run publish without verifying that the token is a least valid is a degradation from the npm whoami check that we were doing previously. without this check, we increase the chances that our users will end up with partial releases that can be unrecoverable, forcing them to skip versions for what actually gets released all the way to the registry.

is there any other way for us to check the validity of a token before attempting to publish? if not today, is there any planned capability that might be coming soon?

travi avatar Aug 22 '25 21:08 travi

👋 Hey @travi this is an understandable request. You want something you can run that can give you an non-zero exit code if the trusted publisher is not setup (keep in mind "validity of a token" is not something we can ping without a publush, but more "can we get a token from the exchange endpoint". npm publish --dry-run does have a verbose log line npm verbose oidc Successfully retrieved and set token, but stdout matching isn't great.

The endpoint is pingable without the CLI, I tried to make the most minimal "code golf" style example that has some legibility that will throw a non-zero exit code if OIDC isn't setup correctly. Does this help as a workaround to check if the package / repository has the OIDC trusted configuration working properly? If this succeeds then a subsequent publish should also succeed.

The only shortcoming here is maybe some compatibility around publishConfig.registry in package.json.

name: Check OIDC Config

on:
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  exchange:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Request GitHub ID token and exchange for npm
        shell: bash
        run: |
          set -euo pipefail
          REG=$(npm -s config get registry||:); REG=${REG%/}; : "${REG:=https://registry.npmjs.org}"
          HOST=${REG#*://}; HOST=${HOST%%/*}
          ID=$(curl -fsS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=npm:${HOST}" | jq -er .value)
          PKG=$(jq -r '.name|@uri' package.json)
          curl -fsS -H "Authorization: Bearer $ID" "$REG/-/npm/v1/oidc/token/exchange/package/$PKG" -d ""

Also: is this something you're looking to bake into semantic-release or something you want to use in your own workflows?

reggi avatar Aug 26 '25 17:08 reggi

is this something you're looking to bake into semantic-release or something you want to use in your own workflows?

the goal with this is to embed directly into the process that semantic-release handles. we could point users to the sort of exchange workflow that you mention and have them pass the resulting token into how semantic-release already works, but we'd prefer to handle that process as part of the npm plugin that we provide.

You want something you can run that can give you an non-zero exit code if the trusted publisher is not setup

i'm realizing that i could have framed this request a bit better. if talking about currently unavailable, but desired, the best solution for us would be a command that could help us verify if either trusted publishing is set up or a valid token is supplied. We want to add the ability to leverage trusted publishing, but we do not want to remove the ability to continue publishing with a token as an alternative. since i had both situations in mind without making that clear, that is where my inconsistent use of "token" comes through in the above description.

keep in mind "validity of a token" is not something we can ping without a publush, but more "can we get a token from the exchange endpoint".

with npm whoami, we were/are able to confirm that a token is "valid" when in the context where a token is provided for use. that falls short of confirming that the token can be used for publishing, but does confirm validity. in the context of using trusted publishing instead of having a token provided directly for use, i agree that "can get a token from the exchange endpoint" should accomplish at least confirming that the auth context is "valid" since an invalid token would not be returned through a successful exchange

The endpoint is pingable without the CLI

we currently depend directly on the cli as a dependency in our npm plugin, so leveraging the cli for a step like this isn't beyond what could be realistic. (i'd prefer to get to a point where we were instead depending on the decomposed pieces of the cli to take steps like publishing, but i havent yet gotten my head around getting there, if the decomposition would even enable this approach). @hashtagchris helped point us at a similar approach as well, so the consistent message seems to be that an approach like that is probably our best bet for now.

npm publish --dry-run does have a verbose log line npm verbose oidc Successfully retrieved and set token, but stdout matching isn't great.

i may investigate this a bit for the oidc path since i've already gone down this path for my experiments to determine viable paths forward. i would really prefer to avoid stdout matching longer term, though.

where this leaves us: if the token exchange path is the best available way to verify that we are working in a valid auth context, we'll need to verify that conditionally. something along the lines of "if a token is provided, check with npm whoami; if not, check through token exchange (possible by first checking which ci service we are running from)". i think that is doable, but is more complex than i'd like. i was hoping for a way to call one service/command to verify that we are good to move forward, regardless of whether auth is being provided as a token or through oidc.

an alternative middleground could possibly be to define the token into the npmrc (as we do now) if it is provided directly, but do the exchange process to get a token as the fallback, then putting it in the npmrc as a normal token. with that in place, we could move forward in a consistent manner for the rest of the process. however, if i understand correctly, we would not be able to call npm whoami in this scenario because it is not enabled (and doesnt really make sense to be) in the context of trusted publishing. please confirm my understanding here in case i'm avoiding this approach when it might be more viable than i realize

travi avatar Aug 29 '25 19:08 travi

with that in place, we could move forward in a consistent manner for the rest of the process. however, if i understand correctly, we would not be able to call npm whoami in this scenario because it is not enabled (and doesnt really make sense to be) in the context of trusted publishing.

probably worth including in the context of this thread, we also make calls to npm dist-tag add, which is also not yet supported with trusted publishing, if i understand correctly. that would prevent us from continuing with our normal steps for both auth contexts as well. we don't use this for all releases, but it is an important part of our workflows that enable publishing to channels other than latest.

what is the best way to request addition of that command/endpoint in the context of trusted publishing? is it already planned for an upcoming release?

travi avatar Aug 29 '25 19:08 travi

this is an understandable request. You want something you can run that can give you an non-zero exit code

as i continue to think through this need, i think what i'm trying to ask for comes down to this, mostly independent of trusted publishing, so maybe it is better to reframe the request a bit.

as mentioned above, since semantic-release is coordinating a release across multiple services in most cases, it cannot atomically release to all locations. failure to complete release tasks in any of those locations is likely to leave the release in a partially complete state. sometimes steps can be manually undone and retried after correcting the reason for a failure, but that depends on how immutable each step is.

for example, a common scenario is that semantic-release pushes the new tag to the scm host, then publishes to the npm registry, then pushes release notes, such as to github releases. if the publish to the registry step fails, the tag has already been pushed. today, we recommend folks delete the tag and retry. however, if the tag pushes successfully, the publish happens successfully, but the addition of the release notes fails, the publish to the registry is immutable, so the overall release cannot be retried. this will become more immutable with the release of github immutable releases because even the tag push might not be reversible.

because of these issues, i'm wondering if there are simply multiple new features (at least npm trusted publishing and github immutable releases) in the ecosystem that make the need for this pre-check a more pressing need. while we were able to get close to this previously with npm whoami, that fell short of confirming the ability to publish beyond knowing that a token was valid and does not accomplish the same goal when using trusted publishing.

while this is most pressing for our goal to support trusted publishing, i'm wondering if reframing independently of that makes this conversation more clear. do you have thoughts around this? is there a better way to attempt to take a step forward with this?

travi avatar Sep 05 '25 19:09 travi

we were successful in releasing a version of our npm plugin that covers the checks as discussed in this thread in https://github.com/semantic-release/npm/releases/tag/v13.1.0

however, i think that implementation highlights even further how valuable it would be for the npm cli to provide a way to verify that a valid auth context is available (either token based or oidc based) so that tools like semantic-release could avoid reimplementing the process that already exists in the cli.

Expand eligible providers for trusted publishing.

this note from this recent announcement is the key concern. for each provider that is added to the list, we would need to expand our verification logic before semantic-release could work with the addition. we would very much rather leverage the work that the cli is already doing to prove the same

is there a potential path toward a future like this? ideally before a bunch of additional trusted providers are added?

travi avatar Oct 24 '25 20:10 travi

is there a potential path toward a future like this?

Yes. This is something we are looking into right now.

wraithgar avatar Oct 24 '25 20:10 wraithgar

awesome, thank you so much! please let me know how the semantic-release team can be helpful

travi avatar Oct 24 '25 21:10 travi