Skip to content

How to create PyPI API tokens

This page describes how to create PyPI API tokens to allow you to publish a Python package to the public PyPI repository.

Info

This document is a goal-oriented "how-to" guide. We have a separate explainer page which goes into more details on the "why" of this process.

Sign in to PyPI

In 1password we have account credentials for two "uis-devops-bot" accounts, one for each PyPI. Each are set up with 2FA and the 2FA tokens are present in 1password. They are both configured with devops-account-recovery@uis.cam.ac.uk as the recovery email address.

This account is the primary owner of all of our published Python packages.

Create a temporary token for the test PyPI instance

Sign into the test PyPI instance using the uis-devops-bot account credentials. Create a new API token with the following settings:

  • Name: Temporary all scopes token to publish [PACKAGE NAME]
  • Scope: Entire account (all projects)

Make sure to copy the API token somewhere safe since it will only be shown to you once.

In the CI/CD settings for the target project on GitLab, add a new variable:

  • Key: TEST_PYPI_API_TOKEN
  • Value: paste in API token
  • Protect variable: yes
  • Mask variable: yes

Create a temporary token for the main PyPI instance

Sign into the main PyPI instance using the uis-devops-bot account credentials. Create a new API token with the following settings:

  • Name: Temporary all scopes token to publish [PACKAGE NAME]
  • Scope: Entire account (all projects)

Make sure to copy the API token somewhere safe since it will only be shown to you once.

In the CI/CD settings for the target project on GitLab, add a new variable:

  • Key: PYPI_API_TOKEN
  • Value: paste in API token
  • Protect variable: yes
  • Mask variable: yes

Protect tags and branches

In the Repository settings for the project:

  • Under "protected branches", confirm that the default branch (main or master) is protected.
  • Under "protected tags", add the wildcard tag "*" as a protected tag.

Why protect tags?

Our common CI pipeline is configured to publish new Python packages when we push a new tag. These protection rules mean that the tag-triggered CI jobs which publish the packages can see the PyPI API tokens but ordinary test jobs on feature branches cannot.

Make a release

Make a release as described in the release how-to.

Replace the API token with a scoped token

PyPI lets you restrict API tokens to particular projects. Now that we've published a project, we want the API token we use to only be able to publish to that project in future.

On the account management page for test PyPI, remove the temporary token created above and create a new one:

  • Name: GitLab CI for [PACKAGE NAME]
  • Scope: Select the appropriate project

Replace the TEST_PYPI_API_TOKEN CI/CD variable with the new API token.

Delete the temporary all scopes token.

On the account management page for the main PyPI, remove the temporary token created above and create a new one:

  • Name: GitLab CI for [PACKAGE NAME]
  • Scope: Select the appropriate project

Replace the PYPI_API_TOKEN CI/CD variable with the new API token.

Delete the temporary all scopes token.

Summary

In this how-to you saw how to create a PyPI token to publish a Python package publicly and how to add the API tokens to an existing project.

Next steps