Automating .NET Package Publishing with NuGet API Keys

Publishing .NET libraries manually is manageable for occasional updates. However, frequent releases or automated CI/CD pipelines demand a more streamlined approach. The standard method involves using the dotnet nuget push command, authenticated with an API key, to upload packages directly to NuGet.org. This process is efficient but hinges on careful management of the API key to prevent unauthorized access and potential repository compromise.

This guide details the essential steps for creating and using a NuGet API key, emphasizing the critical security imperative: never commit your API key directly into your source code repository. Doing so exposes your credentials, potentially allowing malicious actors to publish unauthorized packages under your name or disrupt your release process.

Prerequisites for Publishing

Before you can publish your .NET package, ensure you have the following in place:

  • A .NET Project: The library or application you intend to package must be a valid .NET project.
  • Generated .nupkg File: You need a compiled NuGet package file. This is typically generated during the build process, often located in a path like ./bin/Release/YourPackage.1.0.0.nupkg. You can create this manually using dotnet pack if it's not automatically generated.
  • NuGet.org Account: A free account on NuGet.org is required to publish packages. If you don't have one, sign up at nuget.org.

Creating Your NuGet API Key

The first step in enabling automated publishing is generating an API key from your NuGet.org account. This key acts as your credential for authenticating package pushes.

  1. Sign In to NuGet.org: Navigate to nuget.org and log in to your account.
  2. Access API Keys: Once logged in, go to the API Keys section of your account settings. This is typically found by clicking your username or profile icon and selecting "API Keys" from the dropdown menu.
  3. Create a New Key: Click the "Create API key" button. You will be prompted to configure several options:
    • Key Name: Provide a descriptive name for your API key. This helps you identify its purpose later, especially if you manage multiple keys. For example, "MyProject CI/CD Key" or "Personal Publishing Key".
    • Expiration: Choose an expiration period for the key. It is best practice to set an expiration date, ranging from 30 days to a year, to enhance security. Avoid creating keys with no expiration. You will receive notifications before the key expires, allowing you to generate a new one and update your systems.
    • Scopes: Define the permissions associated with this key. For publishing packages, you need the Push scope. You can restrict this scope further to specific packages or package patterns if desired, but for general publishing, the Push scope is sufficient. Other scopes include Populate/Unlist and Delete, which you should grant only if necessary for your workflow.
  4. Generate and Copy the Key: After configuring the options, click "Generate". NuGet.org will display your new API key. This is the only time you will see the full key. Copy it immediately and store it securely. Treat this key like a password.
Screenshot of NuGet.org API Key creation form with name, expiration, and scope options

Using the API Key for Publishing

With your API key generated, you can now use it with the dotnet nuget push command. There are several secure ways to handle the key, depending on your environment.

1. Using Environment Variables (Recommended for CI/CD)

Storing your API key as an environment variable is the most secure method, especially in automated build environments. Your CI/CD system (like GitHub Actions, Azure Pipelines, GitLab CI) will have mechanisms to manage secrets and expose them as environment variables to your build jobs.

In your CI/CD pipeline script, you would typically set up the API key as a secret variable, then use it like this:

dotnet nuget push YourPackage.1.0.0.nupkg --source https://api.nuget.org/v3/index.json --api-key $NUGET_API_KEY

Replace $NUGET_API_KEY with the name of the environment variable where you stored your key. Ensure this variable is marked as a secret in your CI/CD platform to prevent it from being logged.

2. Using NuGet.Config (Less Secure, Use with Caution)

You can store API keys in a NuGet.Config file. However, this is generally less secure than environment variables because the NuGet.Config file itself might be committed to the repository if not carefully managed. If you use this method, ensure the NuGet.Config file is placed in a location that is not part of your source control or is appropriately ignored by your version control system.

A NuGet.Config file can look like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <!-- Add this to your NuGet.Config file -->
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
  </packageSources>
  <!-- Add your API key here, but ensure this file is NOT committed -->
  <packageSourceCredentials>
    <!-- Replace 'YourUsername' and 'YourApiKey' -->
    <!-- The username can be anything, the key is what matters -->
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json">
      <username>YourUsername</username>
      <password>YourApiKey</password>
    </add>
  </packageSourceCredentials>
</configuration>

When using dotnet nuget push with this configuration, you don't need to specify the API key directly on the command line, as NuGet will read it from the config file. However, reiterate the warning: do not commit this file.

3. Direct Command Line (Least Secure, For Manual Use Only)

For infrequent, manual publishing, you can pass the API key directly on the command line. This is the least secure method as it can appear in shell history or logs.

dotnet nuget push YourPackage.1.0.0.nupkg --source https://api.nuget.org/v3/index.json --api-key YOUR_ACTUAL_API_KEY

Strongly discouraged for automated workflows.

Security Best Practices: Never Commit Your API Key

The single most critical security consideration is preventing your API key from being exposed in your source code repository. A committed API key is a serious security vulnerability.

  • Use Environment Variables: As detailed above, this is the industry standard for CI/CD. Your build system manages the secret, and it's never written to disk in a way that could be accidentally committed.
  • Local Development Secrets: For local development, you can use tools like the .NET Secret Manager tool or environment variables set in your user profile. For example, using the Secret Manager tool:
    dotnet user-secrets set NuGet:ApiKey YOUR_ACTUAL_API_KEY
    
    Then, in your project file (.csproj), you can reference this secret:
    <PropertyGroup>
      <PackageId>YourPackage</PackageId>
      <Version>1.0.0</Version>
      <!-- ... other properties ... -->
      <!-- Reference the secret for local publishing -->
      <NuGetApiKey>$(NuGetApiKey)</NuGetApiKey>
    </PropertyGroup>
    
    When you run dotnet pack or dotnet publish locally, the key will be substituted. Ensure user-secrets.json is not committed.
  • Regularly Rotate Keys: Even if managed securely, it's good practice to rotate your API keys periodically. Set expiration dates when creating keys and plan to generate new ones before they expire.
  • Least Privilege: Grant only the necessary permissions (scopes) when creating an API key. If a key is only for pushing packages, it doesn't need delete or unlist permissions.

What Happens Next?

Once you have successfully pushed your package, it will appear on NuGet.org, ready for other developers to consume. The process, once automated, significantly speeds up the release cycle and reduces the potential for human error associated with manual uploads. By adhering to the security practices outlined, you ensure that your publishing pipeline is both efficient and secure.