Often in Flask applications we want to add login/logout functionality. Depending on the type of application you're creating, you could use sessions or tokens.
render_template
.In their most common format, a 'secret key' is used in the generation and verification of the signature. In this article I'm going to show you a less known mechanism to generate JWTs that have signatures that can be verified without having access to the secret key. Secretkey: Backend server secret key. Use the method above to generate it. Firstsuperuser: The first superuser generated, with it you will be able to create more users, etc. By default, based on the domain. Firstsuperuserpassword: First superuser password. Use the method above to generate it. In your Iterable project, create a JWT-enabled Mobile API key. On your server, set up a way to generate JWTs for individual users. To create them, use the shared secret associated with the API key created in step 1. Create a web service your mobile apps can query to fetch JWTs for specific users.
In this post we'll learn how to add token-based authentication to your Flask apps. But first...
JWT stands for JSON Web Token, and it is a piece of text with some information encoded into it.
The information stored when doing authentication in a Flask app is usually something that we can use to identify the user for whom we generated the JWT.
The flow goes like this:
That last point is important. When we receive a JWT we know to be valid, we know we generated it for a specific user. We can check this using the information stored inside the JWT.
Since we know the user sent us the JWT that we generated when they logged in, we can treat this used as a 'logged in user'.
Any user that does not send us a valid JWT, we will treat as a 'logged out' user.
There are two main libraries for authentication with Flask: Flask-JWT and Flask-JWT-Extended.
Flask-JWT is slightly simpler, while Flask-JWT-Extended is a bit more powerful. Learning one will make learning the other very straightforward.
In this post we'll use Flask-JWT.
To install Flask-JWT, activate your virtual environment and then do:
Then, in the file where your app is defined, you'll need to import Flask-JWT and create the JWT
object. You also need to define app.secret_key
as that is used to sign the JWT so you know it is your app that created it, and not anyone else:
We also have an import for authenticate
and identity
. These two functions are required for Flask-JWT to know how to handle an incoming JWT, and also what data we want to store in an outgoing JWT.
As soon as we create the JWT
object, Flask-JWT registers an endpoint with our application, /auth
.
That means that the simple app in that code already has an endpoint that users can access. By default, users should be able to send POST requests to the /auth
endpoint with some JSON payload:
authenticate
?The authenticate
function is used to authenticate a user. That means, when a user gives us their username and password, what data we want to put into the JWT. Remember, the data we put into the JWT will come back to us when the user sends it with each request.
The flow goes like this:
/auth
endpoint with their username and password as the JSON payload.authenticate
function is called with that username and password. Flask-JWT set this up when we created the JWT
object.Usually in the authenticate
function I check the validity of a user's username and password, and then tell Flask-JWT to store the user's id
inside the JWT.
Something like this:
My authenticate
function accepts a username
and password
. It then goes into the database and finds a user matching that username, and checks the password is correct.
If it is, it returns the user.
Does that mean the user is stored in the JWT?
No. Flask-JWT will take the id
property of the user
object and store that in the JWT.
If your user
object does not have an id
property, you'll get an error.
You can change which property gets stored in the JWT by setting an app configuration property. Learn more in our Flask-JWT Configuration blog post.
identity
?The identity
function is used when we receive a JWT.
In any of our endpoints (except the /auth
endpoint) the user can send us a JWT alongside their data. They will do this by adding a header to their request:
When that happens, Flask-JWT will take the JWT and get the data out of it. Data stored inside a JWT is called a 'payload', so our identity
function accepts that payload as a parameter:
The payload['identity']
contains the user's id
property that we saved into the JWT when we created it. The payload
also contains other things, such as when the token was created, when it expires, and more. For more information, read the 'Payload' section of this post.
Since payload['identity']
is the user's id
—we use that to find the user in the database and return it.
Important: the identity
function is not called unless we decorate our endpoints with the @jwt_required()
decorator, like so:
Inside any endpoint that is decorated with @jwt_required()
, we can access the current_identity
proxy—it will give us whatever the identity
function returns for the JWT we received in this specific request.
Here's a simple app, taken from the official documentation, that you can use to test your Flask-JWT requests.
I would recommend testing different scenarios with Flask-JWT to check what it can return you. For example, what happens if:
Flask-JWT-Extended is very similar to Flask-JWT, but has more configuration options and some more functionality. For example, it allows for token refreshing.
After you're comfortable with Flask-JWT—and if you need those advanced features—read our blog post on Flask-JWT-Extended for more!
I hope you've found this post useful, and you've learned something!
If you want an even better and more digestible set of video tutorials guiding you through creating Flask applications and REST APIs, check out our REST APIs with Flask and Python course. It contains everything you need to develop simple, professional REST APIs easily.
If you sign up to our mailing list below, that's the best way to get access to a discount code—we share them every month with our subscribers!