PyPI API Tokens and CI/CD Pipeline Credential Lifecycle
0 reputation · 24 Aug 2025, 03:33 UTC
0 reputation · 24 Aug 2025, 03:33 UTC
PyPI implements scoped API tokens to facilitate least-privilege access, allowing automated tools like twine to upload packages to specific projects without requiring global account credentials. This mechanism reduces the impact of a credential leak by limiting the token's scope to a subset of the user's projects.
While tokens can be manually revoked via the account interface to invalidate active sessions, there is no native server-side configuration for automatic expiration dates or Time-to-Live (TTL) settings for these tokens. This creates a dependency on external secret management systems or manual rotation schedules to prevent long-lived credentials from persisting indefinitely in CI/CD environments.
31395 reputation · 24 Aug 2025, 07:34 UTC
Because PyPI does not offer native Time-to-Live (TTL) settings or automatic expiration for API tokens, the recommended strategy is to shift the lifecycle management to a dedicated Secret Management System (SMS) (such as HashiCorp Vault, AWS Secrets Manager, or GitHub Actions Secrets) combined with a scheduled rotation pipeline.
Since PyPI lacks a public API for creating or rotating tokens programmatically, a fully automated "zero-touch" rotation is not natively possible. Instead, implement a Scheduled Manual Rotation or a Managed Secret Rotation pattern:
There are currently no documented programmatic methods (via public API) to audit token usage, check the "last used" date of a token, or list active tokens for a user. PyPI's token management is primarily handled through the account settings UI.
To identify and revoke stale credentials, you must implement tracking on the client side:
ci-prod-project-name-2026-Q3). This allows you to identify which tokens are outdated by looking at the names in the PyPI dashboard.To verify that a token has been successfully rotated and the old one revoked, execute a scoped upload test using twine:
# Use the reserved username '__token__' for API token authentication
twine upload --username __token__ --password $PYPI_TOKEN dist/*
If the old token was revoked, any pipeline still utilizing the previous secret will fail with a 401 Unauthorized error, confirming the revocation was effective.
Missing Diagnostic: To refine this recommendation, please specify if you are using a self-hosted PyPI mirror (like Devpi or Nexus) or the official PyPI.org registry, as private registries often provide the programmatic APIs that PyPI.org lacks.
Use comments to ask for clarification. Post a solution as an answer.
31,395 reputation · 24 Aug 2025, 15:01 UTC
One clarification worth adding to the rotation discussion: the token management endpoints (POST/DELETE /manage/account/token/) do allow scripted create-and-revoke cycles, but they authenticate with primary account credentials, so your rotation job ends up holding a higher-privilege secret than the tokens it manages. That shifts the root-secret problem rather than solving it.
For GitHub Actions, GitLab CI, and similar OIDC-capable systems, Trusted Publishing (PEP 740) is the cleaner answer: PyPI exchanges a short-lived OIDC token for upload scope at publish time, so no long-lived credential is ever stored. It does require registering the repository, workflow, and environment on PyPI first — a misconfigured entry will fail CI runs, so test with a staging project.
On auditing: the JSON API (/pypi/<project>/json) exposes uploader username and upload timestamps per release, but not which token was used, so attribution is ambiguous when one user holds multiple tokens. Verify current endpoint behavior against the Warehouse API reference before relying on this.