No-fuss, pure-Python keyring backend for Azure DevOps Artifacts feeds
Project description
artifacts-keyring-nofuss
Minimal, pure-Python keyring backend for Azure DevOps Artifacts feeds.
Replaces the official artifacts-keyring (which wraps a ~100 MB .NET binary) with a
no-fuss, pure-Python implementation — no .NET required.
Install
pip install artifacts-keyring-nofuss
Or for development:
pip install -e .
How it works
When pip, uv, twine, etc. query the keyring for credentials to an Azure DevOps Artifacts feed, this backend:
- Discovers the Azure AD tenant by making an unauthenticated request to the feed
URL and parsing the
WWW-Authenticateheader. - Obtains a bearer token using one of the supported auth flows (see below).
- For user tokens (Azure CLI): exchanges the bearer token for a narrower
VssSessionTokenscoped tovso.packaging. - For service principal tokens (managed identity, SP, WIF): returns the Entra bearer token directly as Basic auth credentials.
- Returns the credentials to the caller.
Auth flows (priority order)
| # | Flow | How it works |
|---|---|---|
| 1 | Environment variable | Reads a bearer token from ARTIFACTS_KEYRING_NOFUSS_TOKEN (or VSS_NUGET_ACCESSTOKEN as fallback). Best for CI and Docker builds. |
| 2 | Azure CLI | Runs az account get-access-token. Most common for local dev. |
| 3 | ADO auth helper | Calls ~/ado-auth-helper (created by the ado-codespaces-auth VS Code extension). Enables seamless auth in GitHub Codespaces. |
| 4 | Workload Identity | Exchanges a federated token via AZURE_CLIENT_ID + AZURE_FEDERATED_TOKEN_FILE + AZURE_TENANT_ID. Best for GitHub Actions with azure/login@v2. |
| 5 | Azure Identity | Uses DefaultAzureCredential from azure-identity. Handles managed identities (system + user-assigned), service principals (secret/cert), workload identity federation, and more. |
Configuration
Select a specific flow
By default, providers are tried in the order above. To force a specific one:
# Environment variable
export ARTIFACTS_KEYRING_NOFUSS_PROVIDER=azure_cli # or: env_var, ado_auth_helper, workload_identity, azure_identity
Or in ~/.config/python_keyring/keyringrc.cfg:
[artifacts_keyring_nofuss]
provider = azure_cli
User-assigned managed identity
Set AZURE_CLIENT_ID to the client ID of the user-assigned managed identity:
export AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
When unset, system-assigned managed identity is used.
Service principal with secret
Set the standard Azure Identity environment variables:
export AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export AZURE_CLIENT_SECRET=your-secret
This requires the azure-identity package (included as a dependency). The service principal must have
permissions on the Azure DevOps feed (e.g. Feed Reader).
Bearer token via environment variable
For CI pipelines and Docker builds, pass a pre-minted bearer token:
export ARTIFACTS_KEYRING_NOFUSS_TOKEN=<bearer-token>
For backward compatibility with existing artifacts-keyring CI configs,
VSS_NUGET_ACCESSTOKEN is also accepted as a fallback.
Workload Identity Federation (GitHub Actions OIDC)
When using azure/login@v2 in GitHub Actions, the action automatically sets
AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_FEDERATED_TOKEN_FILE.
The workload identity provider detects these and exchanges the federated token
for a bearer — no extra configuration needed.
GitHub Codespaces
Add the artifacts-helper
devcontainer feature to your .devcontainer/devcontainer.json:
{
"features": {
"ghcr.io/microsoft/codespace-features/artifacts-helper:3": {}
}
}
This installs the ado-codespaces-auth VS Code extension, which creates
~/ado-auth-helper. The ado_auth_helper provider calls it automatically —
no az login needed. Sign in via the "Click to authenticate" prompt in the
VS Code status bar on first use.
Usage with pip
pip install --index-url https://pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/ my-package
The keyring backend is automatically discovered by pip. No extra flags needed.
Usage with uv
- Install keyring with this backend:
pip install keyring artifacts-keyring-nofuss
# or
uv tool install keyring --with artifacts-keyring-nofuss
- Configure uv to use keyring for authentication. Either add it to your project config:
# pyproject.toml or uv.toml
[tool.uv]
keyring-provider = "subprocess"
Or set the environment variable:
export UV_KEYRING_PROVIDER=subprocess
- Use uv as normal with your private feed. A username in the URL (e.g.
__token__@) is required to trigger keyring lookup:
uv pip install my-package --index-url https://__token__@pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/
This also works with legacy subdomain-prefixed feed URLs:
uv pip install my-package --index-url https://__token__@myorg.pkgs.visualstudio.com/_packaging/{feed}/pypi/simple/
For pyproject.toml index configuration:
[[tool.uv.index]]
url = "https://__token__@pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/"
name = "my-feed"
Supported feed URLs
Any URL whose host matches one of (including subdomain-prefixed variants):
pkgs.dev.azure.com(e.g.https://pkgs.dev.azure.com/myorg/…)pkgs.visualstudio.com(e.g.https://myorg.pkgs.visualstudio.com/…)pkgs.codedev.mspkgs.vsts.me
URLs with userinfo (e.g. https://__token__@host/…) and bare hostnames without
a scheme are also handled correctly.
Troubleshooting
Enable verbose debug output to see the full authentication flow:
ARTIFACTS_KEYRING_NOFUSS_DEBUG=1 pip install --index-url https://pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/ my-package
This prints the provider chain, token exchange steps, and any errors to stderr.
Security model
This package handles authentication tokens. Key security properties:
- Endpoint validation: Discovery responses are validated against allowlists.
The
authorization_uriand VSTS authority must point to known hosts over HTTPS, with no non-default ports, userinfo, or deep paths. The authority must be a clean origin (https://hostorhttps://host/). This prevents bearer token exfiltration via DNS hijacking or rogue proxy responses. - Short-lived tokens: Bearer tokens are not persisted to disk. In-memory caching has a 50-minute TTL (tokens typically live 60–75 minutes).
- Narrow scope: User tokens (Azure CLI) are exchanged for session tokens scoped to
vso.packaging(read-only). Service principal tokens (MI/SP/WIF) are returned directly — scope is determined by the identity's Azure DevOps permissions. - No CWD config: Provider configuration is read only from
~/.config/or environment variables, never from the working directory.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file artifacts_keyring_nofuss-1.1.1.tar.gz.
File metadata
- Download URL: artifacts_keyring_nofuss-1.1.1.tar.gz
- Upload date:
- Size: 26.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d92e79cbce317f5a20f34901db299aa7992340067bdc8a6558b402fc4ea09d45
|
|
| MD5 |
19c74bcd9a235bff49214ccb7a0a5c3a
|
|
| BLAKE2b-256 |
db274afc2b3dfcb92a02af73c779592563c0756e109f569f86e7a23575825a13
|
Provenance
The following attestation bundles were made for artifacts_keyring_nofuss-1.1.1.tar.gz:
Publisher:
release.yml on microsoft/artifacts-keyring-nofuss
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
artifacts_keyring_nofuss-1.1.1.tar.gz -
Subject digest:
d92e79cbce317f5a20f34901db299aa7992340067bdc8a6558b402fc4ea09d45 - Sigstore transparency entry: 1393227974
- Sigstore integration time:
-
Permalink:
microsoft/artifacts-keyring-nofuss@5bb8e4c1895fde7d0775288b55a832bbb46a1c17 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/microsoft
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5bb8e4c1895fde7d0775288b55a832bbb46a1c17 -
Trigger Event:
push
-
Statement type:
File details
Details for the file artifacts_keyring_nofuss-1.1.1-py3-none-any.whl.
File metadata
- Download URL: artifacts_keyring_nofuss-1.1.1-py3-none-any.whl
- Upload date:
- Size: 18.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1047b3f94b0d38b59006171107bd879748083674f2b6b4717dd4ef6d44651704
|
|
| MD5 |
be0614f8b11a80800d9c348b56e33333
|
|
| BLAKE2b-256 |
c0e350c94419151d6e4d2935389ef7e6de7819c7101e2168180c6eae186db240
|
Provenance
The following attestation bundles were made for artifacts_keyring_nofuss-1.1.1-py3-none-any.whl:
Publisher:
release.yml on microsoft/artifacts-keyring-nofuss
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
artifacts_keyring_nofuss-1.1.1-py3-none-any.whl -
Subject digest:
1047b3f94b0d38b59006171107bd879748083674f2b6b4717dd4ef6d44651704 - Sigstore transparency entry: 1393227985
- Sigstore integration time:
-
Permalink:
microsoft/artifacts-keyring-nofuss@5bb8e4c1895fde7d0775288b55a832bbb46a1c17 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/microsoft
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5bb8e4c1895fde7d0775288b55a832bbb46a1c17 -
Trigger Event:
push
-
Statement type: