PyPI security work: multifactor auth progress & help needed

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.


: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!


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


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.


So I just got the email saying one of my projects is deemed critical so will require 2FA. Thankfully (for me) it’s a deprecated project so I’m not making new releases anyway.

FYI I believe the email is really poorly written. Being a plain text email, I initally assumed it was spam. I definitely did not believe it was an official email for a while.

While it has a basic summary of why it’s being done, there’s no links to “read more information about this here”. It took me way too long to find the link to the link to the link to get this this discuss page.

The givaway link at the bottom makes it sound like the key is going to be required, but I’m not in an eligible country to get one (Australia). This was really disappointing. It felt like I had to get to the fine print to find out I can use a standard authenticator app, rather than a frustratingly easy to loose hw key

Lastly, and most importantly, how is this going to affect my 100% gitlab ci automated release process?

In the email it says “required to enable two-factor authentication on their account in order to add new releases or otherwise modify a critical project.”
On first read, this makes it sounds like I’m going to have to 2FA login to release builds. I can categorically state this will block me from making new releases in an automated fashion, which will stop me making releases (to pypi) at all - I’ll tell people to pip install direct from gitlab instead.

Again on the link to the link to the faq there’s a line “This only affects logging in via a web browser, and not (yet) package uploads.” so I gather I don’t need 2FA to upload new packages… doesn’t this defeat the entire purpose of the 2FA protecting the account from nefarious uploads?
but sure I gather I can still CI release (for now) but at some unspecified time in the future all my projects will likely break on release? after I’ve tagged and set off the automated job to upload?

So many questions, so few answers (that I can find).

Reading more info scattered around… my suggestion is:

  • Use a nicer looking (html) email with pypi header etc to at least make it look more official.
  • Open with a positive statement like “Thanks for being a valued member of the python community! One (or more) of your packages is so popular it’s been designated as a critical project on PyPI”. Maybe include a link to details about how these determinations are made for transperancy?
  • Make it clear in the email you can use TOTP app or (preferred) hw key
  • Make it clear in the email that for uploading releases you can already create and use API keys as the current preferred approach.
  • Make it clear in the email that while email:pass can still be used for uploads currently, it is being deprecated for these security reasons.

Yes, it’s a bit confusing. I brought it up in another thread as

When you do eventually set up 2FA for your account, the next time
you upload using your username+password you’ll get a new automated
notification E-mail. That one will inform you that at some
unspecified point in the future PyPI will stop allowing
username+password uploads for accounts using 2FA, and that you
should generate an API token and switch to using that for uploads

What’s still not been made clear is whether “critical” package
maintainers will be prevented from continuing to upload with
username+password if they never add 2FA (understanding that they’ll
be unable to log into the WebUI of course).

Another problem I have is that an account I manage is a maintainer
of many hundreds of projects, several dozen of which have been
flagged as “critical,” but (at least last time I looked) PyPI didn’t
allow me to query or sort my projects by this field, so it’s hard
for me to figure out exactly which ones fall in the critical
category without manually scrolling through many pages of project
listings looking for the little icon. Granted, this problem probably
doesn’t affect all that many users, so I understand if it’s not a

I believe a more general goal is to move away from username + password and to project tokens anyway (but I don’t work on Warehouse, so I could be remembering wrong). But yes, eventually, sometime in the future (which has not been decided upon yet), if your project is flagged as critical you will not be able to upload a new version w/o turning on 2FA. Otherwise what’s the point of (eventually) requiring 2FA to begin with?


I’ve just come back to this issue again, as there have been discussions on the web about whether TOTP apps are sufficiently secure, so I decided to take up the offer of a hardware key. Having got it, I was setting things up and I was mildly frustrated to note that PyPI also supports using your PC or tablet’s biometrics as a 2FA method as well, which is far less hassle. This definitely isn’t clear from the information I’ve seen published, and it would have been realy useful for this to be more obvious somehow[1].

To be fair, I also discovered that github supports biometrics as well, so it’s not just PyPI that’s lacking here - there seems to be a general lack of good, accessible information on effective security practices for the average developer.

Maybe it would be useful for one of the security experts here to write up a blog post or article, explaining how to effectively secure your accounts when working on important open source projects…

One other aspect of all this that I’m still struggling with is password management. I still use a local Keepass database for my passwords, which is secure, but a bit of a pain to use. Are cloud-based password managers considered secure these days? How do I choose a good one (ideally one that supports 2FA and biometrics for accessing my passwords…)?

I know this is a much broader question, but it feeds into the same issue, and if we’re trying to improve the security of PyPI packages, educating users in good, effective practices would go a long way to making the whole thing feel more approachable and less of a “punishment for being popular”.

  1. The keys will still be useful, of course, in case I need to use a device without biometrics. ↩︎

1 Like

I also use Keepass, and every time I look at cloud-based ones it seems like a “who was least-recently hacked” decision, which I’m happier to just avoid and stick with Keepass.

The main downside of keepass for me is that mobile support is a bit dodgy (in particular, the UI on various devices is very inconsistent because they are all independent apps). Also the lack of a cross-platform way of delegating access control to my database to the OS (biometrics, for example) so I don’t have to keep entering that long master password…

Isn’t this more that PyPI and GitHub support WebAuthn and at least some browsers/operatings systems support software tokens with biometrics (e.g. FIDO2 implementations like Apple’s Passkeys)?

Documenting this more clearly would indeed be helpful, the connection between “hardware token” and FIDO2 “software” tokens is not immediately obvious, and more so for Apple’s Passkeys where the primary communication is about replacing passwords and not 2FA.

Quite possibly, but that’s basically my point. Terms like “webauthn” don’t mean much to people (well, to me, at least) and I didn’t even consider that it might mean “works with face/fingerpeint ID”…

To put things in a bit more context, I don’t know what any of your second paragraph means, but I’m sure you’re right :wink:

I use 1Password for a password manager. It costs money (but pretty reasonable in cost), but I think it’s pretty much best in class.


I use 1Password for a password manager. It costs money (but pretty reasonable in cost), but I think it’s pretty much best in class.

FYI 1Password will provide accounts to OSS projects for free (we use it for Bokeh):

I also have/had some minor qualms about cloud password vaults, but given we have a distributed team across the world and the need for a couple of levels of access, there’s not really a workable alternative.