Skip to content

Commit b99b8a2

Browse files
authored
feat(nuget): add trusted publisher support with OIDC authentication (#1727)
* feat(nuget): add trusted publisher support with OIDC authentication Implements NuGet Trusted Publishing to enable secure, keyless publishing using GitHub Actions OIDC tokens instead of long-lived API keys. - Add NUGET_TRUSTED_PUBLISHER and NUGET_USERNAME environment variables - Implement OIDC token exchange with NuGet token service endpoint - Maintain backward compatibility with existing NUGET_API_KEY workflow - Update documentation with setup instructions and requirements * GitLab not supported * fix
1 parent ab572c8 commit b99b8a2

File tree

2 files changed

+70
-7
lines changed

2 files changed

+70
-7
lines changed

README.md

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,30 @@ npx publib-nuget [DIR]
188188

189189
**Options (environment variables):**
190190

191-
| Option | Required | Description |
192-
| --------------- | -------- | ------------------------------------------------------------------------------ |
193-
| `NUGET_API_KEY` | Required | [NuGet API Key](https://www.nuget.org/account/apikeys) with "Push" permissions |
194-
| `NUGET_SERVER` | Optional | NuGet Server URL (defaults to nuget.org) |
191+
| Option | Required | Description |
192+
| ------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193+
| `NUGET_TRUSTED_PUBLISHER` | Optional | Set to any value to use NuGet [Trusted Publisher](https://learn.microsoft.com/en-us/nuget/nuget-org/trusted-publishing) authentication (OIDC). Requires a supported ambient identity (i.e. CI/CD environment). |
194+
| `NUGET_USERNAME` | for Trusted Publisher auth | NuGet.org username (profile name, not email address) for Trusted Publisher authentication. |
195+
| `NUGET_AUDIENCE` | Optional | OIDC audience for token generation (defaults to `https://www.nuget.org`) |
196+
| `NUGET_TOKEN_SERVICE_URL` | Optional | NuGet token service endpoint (defaults to `https://www.nuget.org/api/v2/token`) |
197+
| `NUGET_API_KEY` | Optional | [NuGet API Key](https://www.nuget.org/account/apikeys) with "Push" permissions. Not required when using Trusted Publishers. Also set to use a short-lived NuGet API key via e.g. <https://github.com/NuGet/login> |
198+
| `NUGET_SERVER` | Optional | NuGet Server URL (defaults to nuget.org) |
199+
200+
### Trusted Publishers
201+
202+
NuGet [Trusted Publishers](https://learn.microsoft.com/en-us/nuget/nuget-org/trusted-publishing) allows publishing without API keys by using OpenID Connect (OIDC) authentication between a trusted third-party service and NuGet.org.
203+
204+
**Trusted Publisher Setup:**
205+
206+
1. Configure your NuGet.org project to use a [Trusted Publisher](https://learn.microsoft.com/en-us/nuget/nuget-org/trusted-publishing)
207+
2. Set `NUGET_TRUSTED_PUBLISHER=1` in your workflow environment
208+
3. Set `NUGET_USERNAME` to your NuGet.org username (profile name)
209+
4. No `NUGET_API_KEY` needed
210+
211+
**Requirements:**
212+
213+
* **GitHub Actions**: Your workflow must have `id-token: write` permission.
214+
* **Python 3**: Required when using Trusted Publishers without providing `NUGET_API_KEY`. The `id` package is automatically installed.
195215

196216
**Publish to GitHub Packages**\
197217
You can publish to GitHub Packages instead, with the following options:

bin/publib-nuget

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,57 @@ set -eu # we don't want "pipefail" to implement idempotency
1010
#
1111
# DIR is a directory with *.nupkg files (default is 'dist/dotnet')
1212
#
13-
# NUGET_API_KEY (required): API key for nuget
13+
# Two publishing modes are supported: Trusted Publisher (recommended) and API key (legacy).
14+
# Set environment variables accordingly.
1415
#
16+
# Trusted Publisher (recommended):
17+
# - NUGET_TRUSTED_PUBLISHER (required): set to any value
18+
# - NUGET_USERNAME (required): the NuGet.org username of the package owner
19+
# - NUGET_AUDIENCE (optional): OIDC audience for token generation (defaults to https://www.nuget.org)
20+
# - NUGET_TOKEN_SERVICE_URL (optional): NuGet token service endpoint (defaults to https://www.nuget.org/api/v2/token)#
21+
#
22+
# API Key:
23+
# - NUGET_API_KEY (required): API key for your account, created on nuget.org or use https://github.com/NuGet/login
24+
#
25+
# Generic options:
26+
# - NUGET_SERVER (optional): different NuGet server URL to use
1527
###
1628

1729
cd "${1:-"dist/dotnet"}"
1830

19-
if [ -z "${NUGET_API_KEY:-}" ]; then
20-
echo "NUGET_API_KEY is required"
31+
# Check for Trusted Publisher authentication
32+
if [ -n "${NUGET_TRUSTED_PUBLISHER:-}" ]; then
33+
echo "Using NuGet Trusted Publisher authentication"
34+
35+
if [ -z "${NUGET_USERNAME:-}" ]; then
36+
echo "NUGET_USERNAME is required when using Trusted Publishers"
37+
exit 1
38+
fi
39+
40+
# Install required packages
41+
python3 -m pip install --user --upgrade id
42+
43+
# Generate OIDC token using the id package
44+
nuget_audience="${NUGET_AUDIENCE:-https://www.nuget.org}"
45+
oidc_token=$(python3 -m id "$nuget_audience")
46+
47+
# Exchange OIDC token for NuGet API key
48+
nuget_token_service_url="${NUGET_TOKEN_SERVICE_URL:-https://www.nuget.org/api/v2/token}"
49+
token_request_body=$(jq -n --arg username "$NUGET_USERNAME" '{username: $username, tokenType: "ApiKey"}')
50+
51+
NUGET_API_KEY=$(curl -s -X POST \
52+
-H "Content-Type: application/json" \
53+
-H "Authorization: Bearer ${oidc_token}" \
54+
-H "User-Agent: publib/nuget-publisher" \
55+
-d "$token_request_body" \
56+
"$nuget_token_service_url" | jq -r '.apiKey')
57+
58+
if [ "$NUGET_API_KEY" = "null" ] || [ -z "$NUGET_API_KEY" ]; then
59+
echo "Failed to exchange OIDC token for NuGet API key"
60+
exit 1
61+
fi
62+
elif [ -z "${NUGET_API_KEY:-}" ]; then
63+
echo "NUGET_API_KEY is required or set NUGET_TRUSTED_PUBLISHER=1 with NUGET_USERNAME"
2164
exit 1
2265
fi
2366

0 commit comments

Comments
 (0)