Categories
Python

JWT Authentication with Python and Flask

In our blog post about HTTP Authentication, we promised we would next cover JSON Web Tokens aka JWT based authentication. So we wrote a detailed blog post on The Concepts of JWT explaining how the technology works behind the scene. And in this blog post, we would see how we can actually implement it in our REST API. In case you have missed them, we have also explained the basics of REST APIs  along with a Python / Flask tutorial walking through some of the best practices.

PyJWT or a Flask Extension?

In our last blog post on JWT, we saw code examples based on the PyJWT library. A quick Google search also revealed a couple of Flask specific libraries. What do we use?

We can implement the functionality with PyJWT alright. It will allow us fine grained control. We would be able to customize every aspect of how the authentication process works. On the other hand, if we use Flask extensions, we would need to do less since these libraries or extensions already provide some sort of integrations with Flask itself. Also personally, I tend to choose my framework specific libraries for a task. They reduce the amount of task required to get things going.

In this blog post, we would be using the Flask-JWT package.

Getting Started

Before we can begin, we have to install the package using pip.

We also need an API end point that we want to secure. We can refer to the initial code we wrote for our HTTP Auth tutorial.

Now we work on securing it 🙂

Flask JWT Conventions

Flask JWT has the following convention:

  • There needs to be two functions – one for authenticating the user, this would be quite similar to the verify function we wrote in our last tutorial (http auth tutorial). The second function’s job is to identify user from a token. Let’s call this function identity.
  • The authentication function must return an object instance that has an attribute named id.
  • To secure an endpoint, we use the @jwt_required decorator.
  • An API endpoint is setup at /auth that accepts username and password via JSON payload and returns access_token which is the JSON Web Token we can use.
  • We must pass the token as part of the Authorization header, like – JWT <token>.

Authentication and Identity

First let’s write the function that will authenticate the user. The function will take in username and password and return an object instance that has the id attribute. In general, we would use database and the id would be user id. But for this example, we would just create an object with an ID of our choice.

We are storing the user details in a dictionary like before. We have created User class with id attribute so we can fulfil the requirement of having id attribute. In our verify function, we compare the username and password and if it matches, we return an User instance with the id being 123. We will use this function to verify user logins.

Next we need the identity function that will give us user details for a logged in user.

The identity function will receive the decoded JWT. An example would be like:

Note the identity key in the dictionary. It’s the value we set in the id attribute of the object returned from the verify function. We should load the user details based on this value. But since we are not using the database, we are just constructing a simple dictionary with the user id.

Securing Endpoint

Now that we have a function to authenticate and another function to identify the user, we can start integrating Flask JWT with our REST API. First the imports:

Then we construct the jwt instance:

We pass the flask app instance, the authentication function and the identity function to the JWT class.

Then in the resource, we use the @jwt_required decorator to enforce authentication.

Please note the jwt_required decorator takes a parameter (realm) which has a default value of None. Since it takes the parameter, we must use the parentheses to call the function first – @jwt_required() and not just @jwt_required. If this doesn’t make sense right away, don’t worry, please do some study on how decorators work in Python and it will come to you 🙂

Here’s the full code:

Looks good? Let’s try it out.

Trying it out

Run the app and try to access the secured resource:

Makes sense. The endpoint now requires authorization token. But we don’t have one, yet!

Let’s get one – we must send a POST request to /auth with a JSON payload containing username and password. Please note, the api prefix is not used, that is the url for the auth end point is not /api/v1/auth. But it is just /auth.

Cool, we got the token. Now let’s use it to access the resource.

Whoa, it worked! Amazing, now our JWT authentication is working great!

Getting the Authenticated User

Once our JWT authentication is functional, we can get the currently authenticated user by using the current_identity object.

Let’s add the import:

And then let’s update our resource to return the logged in user identity.

The current_identity object is a LocalProxy instance which can’t be directly JSON serialized. But if we pass it to a dict() call, we can get a dictionary representation.

Now let’s try it out:

As we can see the current_identity object returns the exact same data our identity function returns because Flask JWT uses that function to load the user identity.

What’s Next?

Go ahead and implement the same functionality using PyJWT and your own code. You will need to create an endpoint that encodes current user data and returns the access token. Then you will need to intercept the http headers, parse the Authorization header and verify the JWT token. It should be a fun and yet excellent learning exercise.

 

Categories
General

Understanding JWT (JSON Web Tokens)

In the end of our last post (which was about Securing REST APIs) we mentioned about JWT. I made a promise that in the next post, we would discuss more about JWT and how we can secure our REST APIs using it. However, when I started drafting the post and writing the code, I realized the underlying concepts of JWT themselves deserve a dedicated blog post. So in this blog post, we will focus solely on JWT and how it works.

What is JWT?

We will ignore the text book definitions and try to explain the concepts in our own words. Don’t be afraid of the serious looking acronym, the concepts are rather simple to understand and comprehend. First let’s break down the term – “JSON Web Tokens”, so it has to do something with JSON, the web and of course tokens. Right? Let’s see.

Yes, a JWT mostly concerns with a Token that is actually a hashed / signed form of a JSON payload. The JSON payload is signed using a hashing algorithm along with a secret to produce a single (slightly long) string that works as a token. So a JWT is basically a string / token generated by processing a JSON payload in a certain way.

So how does JWT help? If you followed our last article, you now know why http basic auth is bad. You have to pass your username and password with every request. That is kind of bad, right? The more you send your username and password over the internet, the more likely it is to get compromised, no? Instead, on the first login, we can accept the username and password and return a token back to the client. The client passes that token with every request. We verify that token to see if it’s a logged in user or not. This is the idea behind Token based authentication.

Random Tokens  vs JWT

How would you generate such token? You could generate a nice random string and store it in database against that user. Right? This is how cookie based session works too, btw. Now what if your application is scaled across multiple servers and all requests are load balanced? One server will not recognize a token / session generated by another server. Unless of course you also have one central database active all the time, serving all the incoming requests from all the servers. That setup is tricky and difficult, no?

There is another work around using sticky sessions where the requests from one particular user is always directed to the same server by the load balancer. This work around is also not as simple as JWT. Even if all these work nicely, we still have to make database queries to validate the token / session. What if we want to provide single sign on (users from one service wants to access resources on a different service all together)? How does that work? We will need a central auth server and all services will have to talk to it to verify the user token.

The benefit of JWT is that it’s lightweight but at the same time it’s a self contained JSON payload. You can store user identity in the JSON, sign it and send the token to the clients. Since it’s signed we can verify and validate it with just our secret key. No database overhead. No need for sticky sessions. Just share the secret key privately and all your services can read the data stored inside the JWT. Others can’t tamper or forge a new, valid token for an user without that secret key. Single sign on just becomes a breeze and less complicated. Sounds good? Let’s see how JWTs are constructed.

Anatomy of JWT

A JSON Web Token consists of three major parts:

  • Header
  • Payload
  • Signature

These 3 parts are separated by dots (.). So a JWT looks like the following

If you look closely, there are 3 parts here:

  • Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  • PayloadeyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
  • SignatureTJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Okay, so we get the three parts, but what do they really do? Also those strings look like meaningless characters to me. What are they? How are they generated? Well, they are encoded in certain ways as we will see in the following sections.

Header

The header is a simple key value pair (dictionary / hashmap) data structure. It usually has two keys typ and alg short for type and algorithm. The standard is to have the keys at best 3 character long, so the generated token does not get too large.

Example:

The typ value is JWT since this is JWT we’re using. The HS256 is the most common and most popular hashing algorithm used with JWT.

Now we just need to base64 encode this part and we get the header string. You were wondering why the strings didn’t make sense. That’s because the data is base64 encoded.

Payload

Here comes our favorite part – the JSON payload. In this part, we put the data we want to store in the JWT. As usual, we should keep the keys and the overall structure as small as possible.

We can add any data we see fit. These fields / keys are called “claims”. There are some reserved claims – keys which can be interpreted in a certain way by the libraries which decode the JWT. For example, if we pass the exp  (expiry) claim with a timestamp, the decoding library will check this value and throw an exception if the time has passed (the token has expired). These can often be helpful in many cases. You can find the common standard fields on Wikipedia.

As usual, we base64 encode the payload to get the payload string.

Signature

The signature part itself is a hashed string. We concatenate the header and the payload strings (base 64 encoded header and payload) with a dot (.) between them. Then we use the hashing algorithm to hash this string with our secret key.

In pseudocode:

That would give us the last part of the JWT, the signature.

Glue it all together

As we discussed before, the JWT is the dot separated form of the three components. So the final JWT would be:

 Using a library

Hey! JSON Web Tokens sounded great but looks like there’s a lot of work involved! Well, it would seem that way since we tried to understand how a JSON Web Token is actually constructed. In our day to day use cases, we would just use a suitable library for the language / platform of our choice and be done with it.

If you are wondering what library you can use with your language / platform, here’s a comprehensive list of libraries – JSON Web Token Libraries.

Real Life Example with PyJWT

Enough talk, time to see some codes. Excited? Let’s go!

We will be using Python with the excellent PyJWT package to encode and decode our JSON Web Tokens in this example. Before we can use the library, we have to install it first. Let’s do that using pip.

Now we can start generating our tokens. Here’s an example code snippet:

If we run the code, we will see:

So it worked – we encoded a payload and then decoded it back. All we needed to do is to call jwt.encode and jwt.decode with our secret key and the payload / token. So simple, no? parties.

Bonus Example – Expiry

In the following example, we will set the expiry to only 2 seconds. Then we will wait 10 seconds (so the token expires by then) and try to decode the token.

What happens after we run it? This happens:

Cool, so we get an error mentioning that the signature has expired by now. This is because we used the standard exp claim and our library knew how to process it. This is how we use the standard claims to ease our job!

Using JWT for REST API Authentication

Now that we’re all convinced of the good sides of JSON Web Tokens, the question comes into mind – how can we use it in our REST APIs?

The idea is simple and straightforward. When the user logs in the first time, we verify his/her credentials and generate a JSON Web Token with necessary details. Then we return this token back to the user/client. The client will now send the token with every request, as part of the authorization header.

The server will decode this token and read the user data. It won’t have to access the database or contact another auth server to verify the user details, it’s all inside the decoded payload.  And since the token is signed and the secret key is “secret”, we can trust the payload.

But please make sure the secret key is not compromised. And of course use SSL (https) so that men in the middle can not hijack the token anyway.

What’s next?

JSON Web Token is not only about authentication. You can use it to securely transmit data from one party to another. However, it’s mostly used for authenticating REST APIs. In our next blog post, we shall go through that use case. We will see how we can authenticate our api using JWT.

In the mean time, you can subscribe to the mailing list so you can stay up to date with this blog. If you liked the article and/or learned something new, please don’t forget to share it with your friends.

Categories
Python

Securing REST APIs: Basic HTTP Authentication with Python / Flask

In our last tutorial on REST API Best Practices, we designed and implemented a very simple RESTful mailing list API. However our API (and the data) was open to public, anyone could read / add / delete subscribers from our mailing list. In serious projects, we definitely do not want that to happen. In this post, we will discuss how we can use http basic auth to authenticate our users and secure our APIs.

PS: If you are new to REST APIs, please check out REST APIs: Concepts and Applications to understand the fundamentals.

Setup API and Private Resource

Before we can move on to authentication, we first need to create some resources which we want to secure. For demonstration purposes, we will keep things simple. We will have a very simple endpoint like below:

If we launch the server and access the endpoint, we will get the expected output:

Our API is for now public. Anyone can access it. Let’s secure it so it’s no longer publicly accessible.

Basic HTTP Authentication

The idea of Basic HTTP Authentication is pretty simple. When we request a resource, the server sends back a header that looks something like this: WWW-Authenticate →Basic realm=”Authentication Required”. Generally when we try to access such resources from a browser, the browser shows us a prompt to enter username and password. The browser then base64 encodes the data and sends back an Authorization header. The server parses the data and verifies the user. If the user is legit, the resource is accessible, otherwise we are not granted permission to access it. 

While using a REST Client, we would very often need to pass the credentials before hand, while we make the request. For example, if we’re using curl, we need to pass the --user option while running the command.

Basic HTTP Authentication is a very old method but quite easy to setup. Flask HTTPAuth is a nice extension that would help us with that.

Install Dependencies

Before we can start writing codes, we need to have the necessary packages installed. We can install the package using pip:

Once the package is installed, we can use it to add authentication to our API endpoints.

Require Login

We will import the HTTPBasicAuth class and create a new instance named auth. It’s important to note that name because we will be using methods on this auth instance as decorators for various purposes.  For example, we will use the @auth.login_required decorator to make sure only logged in users can access the resource.

In our resource, we added the above mentioned decorator to our get method. So if anyone wants to GET that resource, s/he needs to login first. The code looks like this:

If we try to access the resource without logging in, we will get an error telling us we’re not authorized. Let’s send a quick request using curl.

So it worked. Our API endpoint is now no longer public. We need to login before we can access it. And from the API developer’s perspective, we need to let the users login before they can access our API. How do we do that?

Handling User Logins

We would generally store our users in a database. Well, a secured database. And of course, we would never store user password in plain text. But for this tutorial, we would store the user credentials in a dictionary. The password will be in plain text.

Flask HTTP Auth will handle the authentication process for us. We just need to tell it how to verify the user with his/her username and password. The @auth.verify_password decorator can be used to register a function that will receive the username and password. This function will verify if the credentials are correct and based on it’s return value, HTTP Auth extension will handle the user auth.

In the following code snippet, we register the verify function as the callback for verifying user credentials.  When the user passes the credentials, this function will be called. If the function returns True, the user will be accepted as authorized. If it returns False, the user will be rejected. We have kept our data in the USER_DATA dictionary.

Once we have added the above code, we can now test if the auth works.

But if we omit the auth credentials, does it work?

It doesn’t work without the login. Perfect! We now have a secured API endpoint that uses basic http auth. But in all seriousness, it’s not recommended.  That’s right, do not use it in the public internet. It’s perhaps okay to use inside a private network. Why? Please read this thread.

Wrapping Up

With the changes made, here’s the full code for this tutorial:

As discussed in the last section, it’s not recommended to use basic http authentication in open / public systems. However, it is good to know how http basic auth works and it’s simplicity makes beginners grasp the concept of authentication / API security quite easily.

You might be wondering – “If we don’t use http auth, then what do we use instead to secure our REST APIs?”. In our next tutorial on REST APIs, we would demonstrating how we can use JSON Web Tokens aka JWT to secure our APIs. Can’t wait for that long? Go ahead and read the introduction.

And don’t forget to subscribe to the mailing list so when I write the next post, you get a notification!