PyPI security work: multifactor auth progress & help needed

You can now use API tokens to upload packages to PyPI and Test PyPI! Warning that this is a beta feature. More details on the wiki and PyPI’s help section.

This is a first step to enforcing that Users with Two-Factor Authentication enabled will require API Tokens to upload, rather than just their password sans second factor.

Once the beta period for API Tokens is complete, we will notify parties with Two-Factor Authentication enabled that uploads for their projects will require API Tokens. After a suitable waiting period we will then begin to enforce this restriction and include a notice in the error message returned to clients.

Please do test this while it’s in beta. Lead developer William Woodruff says, “Our current auth-policy is drop-in compatible with Twine and distutils. When using a token, your “username” will be @token and your “password” will be the token itself.” So, if your token is pypi:Ab9GpH-H5y your command will be:

twine upload --repository-url  -u @token -p pypi:Ab9GpH-H5y dist/*

(but actual tokens are 160+ characters long).

API tokens also support scoping! To ensure that your newly created tokens only contain the minimum permissions they require, make sure to select the package you’d like to use them with on the creation page. By default, newly created tokens will have “user” scope, meaning that they’ll behave exactly like your password. Once created, the permissions associated with a token cannot change, the token can only be revoked.

We’d particularly like testing from:

  • Orgs that automate uploads using continuous integration
  • People who save PyPI credentials in a .pypirc file
  • Windows users
  • People on mobile devices
  • People on very slow connections
  • Organizations where users share an auth token within a group
  • 4+ maintainers or owners for one project
  • Use an unusual TOTP app or U2F token
  • Usually block cookies and JavaScript (note that you can’t set up a U2F key without JavaScript)
  • Maintain 20+ projects
  • Created PyPI account 6+ years ago

Worked for me. I put the token in ~/.pypirc and uploaded a new release of cryptacular. I like it.

:white_check_mark: 20+ projects
:white_check_mark: PyPI account is old as dirt
:white_check_mark: .pypirc


Are there plans to change this default so that using such a strong token is not the default so that people have to opt into it? (I’m no security expert so this is more inquisitive.)

1 Like

I tried to make a a beta release for geck… and realized I had just pasted my other api token, whoops.

Now I have the correct one and everything works great :+1: Excellent job everyone!

Great question @brettcannon - I filed an issue to follow up.

Thanks to everyone who’s been testing the new feature!


Uploaded a pet project with flit. Works great; just need to set FLIT_USERNAME and FLIT_PASSWORD envs variables, and Token with single project scope.

  • People who save PyPI credentials in a .pypirc file
  • Maintain 20+ projects (but only tried 1 project so far)

Try also to modify the token or the username and the upload was (almost) corectly refused with non-cryptic error messages. :+1:

1 Like

:white_check_mark: Orgs that automate uploads using continuous integration

Deployed fine to Test PyPI and production PyPI from Travis CI with API tokens scoped to a single project. Created the API token and encrypted with travis encrypt "pypi:A..."

One gotcha: if deploying to both Test PyPI and PyPI, remember to create an individual API token on both servers!


I have a feature request of this: Please make it possible to scope the token to multiple projects.

The reason for this: I have a project (PyObjC) that generates multiple distributions on PyPI, which currently requires either a user-scoped token, or multiple tokens.

@ronaldoussoren, would you mind filing a feature request?

As a workaround in the meantime, you could create a separate pyobjc-deployer user that has the “Maintainer” role for all these projects, and create an account-wide token for that user instead.

1 Like

Sure. I’ll file a feature request later this week.

A blog post about API tokens, with screenshots, is up at & mirrored to the PSF blog & tweeted. Please spread the word!

Heads-up for people trying the beta of uploading with API tokens:

  • The Travis problem in #6287 means we’ll probably be changing the token prefix and the username you use for uploads. We may also end up changing other stuff. It’s a beta!
  • Here’s where I’m tracking what we need to fix before I declare the beta done.

Summary: In the last two weeks, we’ve deployed a beta of the API upload key feature, and made more progress on accessibility and multifactor auth.

2FA: So, first off, thanks for helping spread the word about 2FA. The percentage of logins to PyPI that use 2-factor auth:

  • May overall: 2.25%
  • June overall: 3.08%
  • July overall: 4.54%
  • August so far: 11.61%

We aren’t out of the WebAuthn support beta yet because we’re still fixing stuff, like UI, instruction text, and email verification guidance, and the beta badge.

API tokens: We launched the beta of scoped upload API tokens and started getting the word out to get testing, and started fixing things like the syntax of the username and token prefix used to upload, and using normalized project names. On regular PyPI, 106 users have created a total of 123 tokens since launch. 55 tokens are scoped to a single project, while 68 are scoped with the same upload privileges as the creating user (permissions for all of the user’s projects). That’s very helpful as we shake the bugs out – thank you!

Audit log: We made initial decisions on our audit log architectural design and @woodruffw has a work-in-progress pull request that we’re reviewing now (doesn’t yet have UI/UX, or complete tests for results of event recording calls). I believe we’re on track to deploy a beta of this feature this month.

Accessibility: And we kept making accessibility improvements: removing directional copy, fixing a11y in project management tables, defining type on buttons, updating markup on the classifiers page, fixing a11y on the error/404 page, and so on. Pretty soon I’ll be coordinating with @nlhkabu to get some user testers, especially people who use screenreaders, to find the next round of issues.

Scope: We’re trying to keep things scoped pretty tight, so we confirmed that some nice-to-have features are out of scope for this grant.

Thanks: thanks to @alex_Gaynor, sayanarijit, serhii73, @hugovk, @pganssle, Dustin, Ernest, Donald, @webknjaz, graingert, and minho42 who contributed code or reviews recently, and thanks to @nedbat, jheld, Carreau, ZaxR, @ronaldoussoren, glyph, johnsyweb, & bryevdv for opening bugs!

How you can help:

  • Please keep an eye on your email if you have been testing API tokens. As we change token format, if you have a token that we’re invalidating, we’ll notify you.
  • If you or someone you know has accessibility needs for websites (vision, motor control, or otherwise), and might have 30 minutes for Nicole to walk through a user test with them, please introduce them to Nicole.

More in two weeks! Ongoing notes on the wiki.

1 Like

:white_check_mark: Orgs that automate uploads using continuous integration

Retested after

username: @token => __token__
password/token: pypi:<base64 token body> => pypi-<base64 token body>

  • Created a new API token on Test PyPI
  • Updated .travis.yml to use user: __token__ (no quotes this time)
  • Created the password with travis encrypt pypi-A... (again no quotes this time) and put in .travis.yml as password: secure: "S..."
  • Pushed a commit, and it deployed successfully to Test PyPI

:white_check_mark: Orgs that automate uploads using continuous integration

And still working (on Test PyPI) after the old @token/pypi: cases have been removed from Warehouse (

You can now see logs of sensitive events for your user account, and for projects you own, on PyPI and Test PyPI! It’s a new beta feature so please test it and tell us about bugs.

Blog post with more details, things to test. Known issue: we don’t yet log failed authentication attempts.


Hi, all!

Summary: we’re calling our security work for this grant complete, and turning our attention to localisation and accessibility.

In the last month, we deployed a beta of the audit logs feature and delivered further improvements to multifactor authentication and API token features, such as disallowing TOTP code reuse within a window, guarding macaroon deserialization, and improving the syntax of the API token name and prefix.

The team prioritized issues in early August and again in late August to ensure an on-time finish at the end of September.

We continue to receive feedback via user tests and bug reports. So our WebAuthn support, API token support, and audit log support is not yet out of beta and we’re continuing to fix issues (such as this open PR to use semantic forms for WebAuthn actions. I’ve created the Beta blockers milestone to track the few issues I believe block these features from being the caliber – in UX, developer experience, and documentation – that we’d call production-quality. As betas go, these features are pretty stable, so soon I’ll be sending out an announcement email about them.

However, since the vast majority of users are using WebAuthn, TOTP, API tokens, and audit logs without any issues, and since we need to shift our attention to accessibility and localization work, we declare that the OTF security work milestone is now complete.

I’ll be starting a new thread focusing on the localisation and accessibility work.

Thanks to @woodruffw and @nlhkabu for your work! And thanks especially to @EWDurbin, @dustin, sterbic, @pradyunsg, @yeraydiazdiaz, DavidBord, @hugovk, and Peter Stensmyr for helping with code and review in the last month.

If anyone would like to help, please take a look at the issues that need discussion!

1 Like

I meant to mention: @nlhkabu and @woodruffw also spoke about our work on two podcasts: FLOSS Weekly and Podcast.__init__.

1 Like

Summary: API tokens and all our 2FA methods are out of beta!

The auth security features we worked on, funded by the Open Tech Fund – two-factor authentication methods and API tokens for upload – are now out of beta on PyPI!

If you maintain or own a project on the Python Package Index, you should start using these features. Click “help” on PyPI for instructions (2FA, tokens).

(These features are also available on Test PyPI.)

Future: In the future, PyPI will set and enforce a policy requiring users with two-factor authentication enabled to use API tokens to upload (rather than just their password, without a second factor). We do not yet know when we will make this policy change.

Help us out: We’d love your help refining and implementing related features & fixes:

Thanks to the Open Technology Fund for funding this work. And thanks to all the folks I’ve thanked earlier in this thread. :slight_smile:

And more donor-funded work is in progress on pip and PyPI; other threads will have progress reports & details.


More on this in a more recent discussion.