Client and User API Authetication for Django, Android and iOS apps

While working on a recent project, I found myself in a situation where me and my team had to implement the security authentication layer on the server side to make sure only the authenticated client applications (android and iOS mobile apps in our case) and authenticated users have access to the data. As anybody else would, we started to research on the best practices and how other people in the industry have implemented such authentication.

We had used Django Rest Framework to implement our API resources and as it is one of the most known/used packages to implement APIs with Django Framework, I thought we would easily find the information we are looking for. But to my surprise all our google searches ended up in blogs and stackoverflow answers that showed how to implement authentication, which we already had an idea about.

We could not find a single example that showed us how these authentication would work with different types of clients e.g. web, android & ios. Once we failed in gathering the information we required, we decided to identify our core requirements and come-up with the best possible solution for us.

We had only 2 major requirements:

  • Client Authentication – Only allow our own clients (web and mobile apps) to access the APIs.
  • User Authentication – Only allow authenticated users to access the APIs.

Client Authentication

We wanted to make sure that only our own mobile apps are allowed to use our API end points and most of the examples in our research just showed implementation of authentication for users we knew we’d need to work more on this one. Even Django Rest Framework had built in classes to be used for user authentication and that’s what you can find in the documentation, we knew we’d need to implement customised models and logic for client authentication.

So we started off with defining a custom APIClient model as follows:

So whenever a new APIClient object is created, it will automatically generate a key and a secret and add it as an attribute to the object.

So For example, we’ll create a new APIClient for our android app as follows:

and then we provide client.key and client.secret to our android development team as they will need then while requesting an access token for their app.

The idea behind is, that we provide different clients with credentials (key and secret) just like a user has a username and a password. Then just like user authentication they give us the key and the secret and on the backend we decide whether this APIClient should have access to our API’s or not.

If the key and secret exist, match, are valid and are not expired yet, we provide the client with an encrypted access_token which they have to include in the request headers to access the API resources.

In order to achieve the above we’d now start off with implementing an API resource that authenticate the given key and secret and provide the clients with an access token if their request is valid.

The above view will return a valid access token to the client if they provide valid credentials (key and secret) in their request data. Once they have an access token they can include it in the request headers to access the data through the API resources.

Now we will implement the logic that determines whether the given access_token in the request is valid or not and if we should give the request access to our data. To do so we will create a custom authentication class that extends Django rest framework’s base authentication class.

The above class now can be used with the API views where we want to implement the client authentication and in case the request contains a bad access_token we will return 401 Unauthorized response to the client.

The above implementation can only be used for requests that require just the client authentication. But there are a lot of views where we would want to authenticate both the client and the user. And as rest framework would pass the authentication if any one of the authentication passes, We’d need to implement another authentication that authenticates both the client and the user for such views.

For endpoints where we required both the client and the user authentication we’d simply use the above class in the authentication_classes property of the APIView and for public endpoints where we do not require user authentication we’d use ClientAuthentication class.

If you are using this document as a reference to your work, Please do note the following points:

  • This is just a basic authentication implementation on the ORM end and you can additionally secure your data by implementing a security layer on the server end.
  • Make sure you use the above implementation with the SSL protocol i.e. over https as the communication over this protocol is encrypted and thus secure. Using such implementation over http is as good as having no authentication implementation’

If you have any questions or suggestion, Please do comment below.

Update:

Following is the requested utils package used in the examples below. Some of the code might have changed in the following package over time but this will give you a basic idea.