Skip to content

Migrate to NuGet.org Trusted Publishing (OIDC) #7

@Seramis

Description

@Seramis

Description

We currently publish NuGet packages using a static NUGET_API_KEY. We need to migrate this process to use NuGet.org's trusted publishing feature (OIDC). This method enhances security by eliminating the need to store long-lived API keys.

This migration is split into two parts: Part 1 updates the workflow file and can be merged immediately. Part 2 involves configuring NuGet.org and should be done right before the next release to avoid any token/trust expiration issues.

Official Documentation:


Part 1: Prepare Workflow and Secrets (Can be done now)

This part updates the repository's workflow file to use OIDC and adds the necessary secret, preparing the file for the switch. It won't break the current NUGET_API_KEY publishing yet.

1. Configure Repository Secret

  • Go to Settings > Secrets and variables > Actions.
  • Add a new repository secret named: NUGET_USER
  • The value of this secret should be the username (typically your email address or account name) of the NuGet.org account that owns the package(s).

2. Update publish-nuget.yml

  • In .github/workflows/publish-nuget.yml, find the publish job.

  • Add the permissions block to the publish job (this is required for OIDC token issuance):

    jobs:
      publish:
        runs-on: ubuntu-latest
        permissions:             # Add this block
          id-token: write
    
        steps:
          - name: Checkout code
            # ... rest of the steps ...
  • Add a new step that uses the NuGet/login@v1 action to exchange the OIDC token for a temporary API key. Place this step before the "Publish to NuGet" step:

    # ... previous steps (e.g., build, pack) ...
    
        - name: NuGet login (OIDC → temp API key)
          uses: NuGet/login@v1
          id: login
          with:
            # This secret is configured in step 1 of Part 1.
            user: ${{ secrets.NUGET_USER }}
    
        # The next step will now use the output of this 'login' step.
  • Update the "Publish to NuGet" step to remove the static secrets.NUGET_API_KEY and use the temporary key generated by the NuGet/login step:

    • Before:

      - name: Publish to NuGet
        run: dotnet nuget push ./output/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
    • After:

      - name: Publish to NuGet
        # IMPORTANT: Use the output of the 'login' step (steps.login.outputs.NUGET_API_KEY)
        run: dotnet nuget push ./output/*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
  • Merge these changes into the main branch. The workflow will still use the old static key if present, or it will now be prepared for the OIDC switch.


Part 2: Go-Live at Next Release (Do all at once)

Perform these steps when you are ready to publish the next package version and fully switch to Trusted Publishing.

1. Configure nuget.org Trusted Publisher

  • Go to nuget.org and log in to the account that owns the package(s).
  • Navigate to Manage Account > Trusted Publishers.
  • Add a new trusted publisher with the following details:
    • GitHub Owner: ByteAether
    • GitHub Repository: Ulid
    • GitHub workflow file: publish-nuget.yml
    • GitHub environment: Leave this field blank (unless you are using a protected environment).

2. Trigger Publish & Verify

  • Trigger the release workflow (e.g., by publishing a new release or using workflow_dispatch).
  • Go to the "Actions" tab and confirm the workflow runs successfully.
  • Check the workflow logs for the "NuGet login" and "Publish to NuGet" steps to ensure they completed without errors.
  • Verify the new package version is visible on nuget.org.

3. Cleanup (If organization doesn't use NUGET_API_KEY anywhere anymore)

  • After verifying the new publishing method works, go to Settings > Secrets and variables > Actions.
  • Delete the old NUGET_API_KEY repository secret. Do not delete NUGET_USER.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions