Over the past few years I’ve found myself spending an awful lot of time building Flask websites and API services. As someone who came to Flask from Django, I loved Flask for its simplicity, flexibility, and elegance. Since it doesn’t come coupled with many required components, Flask can be a strategic tool for writing to-the-point code, working with new technologies (NoSQL data stores, etc.), and maximizing code base maintainability over time.
Flask’s Biggest Problem
Unfortunately, while Flask is an excellent framework, it has one fatal flaw: authentication. As someone who’s been writing Flask apps since practically day 1, the single largest problem I’ve seen in the community and ecosystem is lack of a good authentication framework.
If you are a Flask developer right now, and in the process of figuring out how to build support for user accounts (and user data) into your application: I can’t help but think you’re going to have a difficult time. Why? Because you’re essentially limited to a few (subpar) choices:
Force Your Users to Use Social Login
One of the most popular authentication strategies in the Flask community is to force your users to log in via Facebook, Twitter, or Google. As a developer, this mean you don’t have to worry about user account management, and can more or less rely on your social provider to handle the complicated bits for you.
The most popular way to handle social login is with the Flask-OAuth library. Unfortunately, this piggybacks off the python-oauth2 library, which is no longer maintained. There are, of course, other issues with this as well, namely:
python-oauth only supports Oauth 1.0a.
python-oauth doesn’t seem to be getting updated to support provider changes (social providers seem to break Oauth implementations quite often).
Oauth has some security issues (although, to be fair, Oauth 1.0a is a lot more secure than Oauth 2.0).
Social providers tend to break Oauth implementations a lot.
And of course, the biggest issue with forcing your users to rely on social login is that you still need to implement your own user data storage: database tables, handle user relationships and security, etc.
In short: Oauth integration is more of a bandaid than a solution – and a poor one at that. Unless you know you need social login, you should not use Oauth as a replacement for user management.
NOTE: Am I the only one who finds social login really annoying on most websites? Unless you’re running a social site, the idea granting a company access to all my personal data feels bad.
Roll Your Own User Authentication
I personally consider rolling your own user authentication in Flask to be the single greatest mistake new Flask developers make. There are many examples floating around on the internet (just Google Flask + authentication and you’ll see a few) which explain how to do the following:
Set up a SQLite3 / MySQL / PostgreSQL database server.
Write a User model (and define a users table).
Build your own login view code to create new user accounts, and store them in the database.
Implement your own crypto, usually by importing from the werkzeug library and hashing user passwords yourself.
Hashing user passwords when they attempt to login, then comparing these hashes to the database.
Storing custom user data either in the same database table as your accounts, or relating it via a foreign key.
Handling database migrations to allow you to add new fields to user accounts
Storing user data in cookies and sessions directly to handle logged-in state.
See where this is going? Of course you do!
Almost nobody hashes passwords correctly.
Almost nobody structures their user database to allow for scaling.
Almost nobody stores user data in a way that allows for future-proofing your database schema – most developers manually change their database schema each time they want to add new user data into their project.
Almost nobody handles user sessions correctly.
Almost nobody locks down their database servers in such a way that it is impossible (or nearly impossible) for attackers to gain access.
Even when people DO get all the above right, almost nobody properly deploys their application such that user credentials are protected over the wire (HTTPS, HSTS, etc.).
There are simply so many things required for proper user authentication that it’s no wonder even some of the largest corporations (with their own security departments, mind you), routinely have data breaches and leak sensitive data. Millions of users are affected by security breaches every year, and as developers, we are entirely at fault.
Building on Top of Flask-Login
The last form of user authentication I’ll discuss is Flask-Login. Unlike the Oauth issues that plague Flask developers, and unlike the 100% roll your own authentication developers, Flask-Login is one of the best ways to at least get you started with authentication.
Flask-Login, unlike the aforementioned solutions, is an abstract authentication framework. Flask-Login provides you with some base classes and a general abstraction of user sessions, login, and logout – all you have to do is implement your own users behind the scenes.
Unfortunately, even though Flask-Login provides some very useful tools to make the authentication problem easier, it still falls short of providing a one-size-fits all solution for developers: you still need to roll your own custom authentication behind the scenes:
Build your own user model.
Define your database schema / etc.
Handle storing custom user data on your own.
Build your own library (of sorts) on top of Flask-Login to get functionality working.
Hope you don’t make any mistakes along the way.
In reality, there’s still a huge void in the authentication space, even with Flask-Login around to help.
Recap and Thoughts
Flask is an excellent framework, plagued by lack of proper authentication support, and the existing, and commonly used attempts to solve this problem, are not suitable solutions.
In the next part of this series I’ll discuss my own attempt at solving this problem: the new Flask-Stormpath library.
If you have any questions, comments, or suggestions – please leave them in the comments below, or feel free to email me directly: randall@stormpath.com
Furthermore, if you’d like to get notified when the next article in this series comes out, don’t forget to subscribe to our blog! http://stormpath.com/blog/feed