Most of the modern web applications are not stand alone services, but utilise the capabilities of others' services and focus on solving its core problem well. That is a bit confusing. what do I mean by that? For example most of the web applications allow you to login with your google or facebook accounts. They leave away the hectic tasks of maintaining the user profile information, password management etc. to the services that already do it well. To take another example, most commuting, location based services use google maps (without the need to build their own maps) in their applications, and they put all their efforts on the problem they want to solve.
Let us say you provide a service that needs the user to register himself and create an account. A new visitor who just want to try things might not want to go through the process of registration. He/she might be more inclined to create an account if it does not involve filling up 10 fields, verifying passwords, verifying emails and jumping between browser tabs. You want to let them use their already existing google of facebook accounts. That means you should be able to authenticate them to, say Google, on their behalf. The obvious idea (which was a norm long ago) is to ask their username and password and try logging in to Google to see if that works. Then get their information. But asking and storing the passwords is a risk that you might not want to take. Moreover, how can user trust you with their username and password? And what if he/she changes his/her password? You will not be able to access their information.
The solution here is to use OAuth2 protocol. This is how it works in abstract.
Now if we want to provide the same capabilities (as that of Google in our case) to our services, we need to implement the OAuth2 protocol which is defined in RFC 6749. But of course, we do not need to build that from scratch. We are going to use Django OAuth Toolkit which provides all the capabilities out of the box.
Install it with
pip install django-oauth-toolkit django-cors-middleware
We will also be needing
django-cors-middleware. Then add it to the
INSTALLED_APPS = [ # Other apps 'oauth2_provider', ]
Set the URLs as follows, with the url space of your choice. Do not forget to set the URL namespace to
urlpatterns = [ # Other urls url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')), ]
Add the CORS middleware and enable it.
MIDDLEWARE = [ # Other middleware 'corsheaders.middleware.CorsMiddleware', # Other middleware ] CORS_ORIGIN_ALLOW_ALL = True
Finally migrate the app with
python manage.py migrate. We are done with the setup and ready to build our service.
Create a user and login. Assuming that the server is running at
http://localhost:8000, visit http://localhost:8000/o/applications/. You should see a screen like this.
Click on click here to register a new application. Fill in the form, choose client type as confidential and Authorization Grant Type as authorization-code for this tutorial. Use
http://django-oauth-toolkit.herokuapp.com/consumer/exchange/ in Redirect Uris. This is the consumer provided by django-oauth-toolkit to make our testing easy. Now, save the app.
You will be seeing a page like this. Copy the Client Id and Token.
We haven't built any service (API endpoints) yet, but our OAuth authorization server is ready already. To use this, we need to write a consumer application. Fortunately django-oauth-toolkit provides us with a consumer service for our testing purposes.
Visit the consumer page and fill in the fields, Client Id with our OAuth app's client id and Authorization url with
http://localhost:8000/o/authorize. Submit the form. The app shows a page with a link (to which our client application - when we build it - should automatically redirected to).
Follow the link and you should be redirected to your local django server page and see a form like this (you will be asked to login if you aren't already).
(The next steps must be done in quick succession, so better read the whole paragraph before switching to the practical session) Click on authorize to grant permissions to the application. This page will again be redirected to the consumer app, and you should see that an authorization token is passed to this page (the consumer). Now, the consumer can use this authorization token to get an access token from our service provider. I know there are too many tokens to remember here. This authorization token expires quickly (60 seconds in our case). This step of obtaining access token must be (there is no reason not to) automated by a consumer application. To get the access token fill in the application's Client id, Client secret and the field Token URL to
http://localhost:8000/o/token/ and then submit the form.
The consumer receives the access token.
Now that the consumer has obtained the access token, it should be able to make use of our OAuth protected services (APIs) on our user's behalf. Let us see, how to build the protected API endpoints.
We will use the generic views that Django OAuth Toolkit provides to create our protected API endpoints. Create a view as follows.
from django.http import HttpResponse from oauth2_provider.views.generic import ProtectedResourceView class MyProtectedEndPoint(ProtectedResourceView): def get(self, request, *args, **kwargs): return HttpResponse('Hello, there!!')
And add the view to your URL configuration and try to visit the url in the browser. You will see a 403 error stating that access is denied. Something like this.
We can also use a client program like curl to send a get request with the command
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://localhost:8000/api/posts/protected_view/
The result will look like this.
Now this end point must be accessible to the consumer when it provides the access token. Visit the consumer page, fill in the API Url and Access Token. Before clicking the 'GET' button open your browser's network tab in developer tools (Ctrl+Shift+i in google chrome), then click on 'GET'. The response should be a '200 OK'.
We can verify the result in the network tab.
We can test this with curl by passing the access token as part of the Authorization Bearer Token with command
curl -i -H "Accept: application/json" -H "Authorization: Bearer aVVkoxH600GX0L8yh0wO06EhCFWeVA" -H "Content-Type: application/json" -X GET http://localhost:8000/api/posts/protected_view/
The result should look something like this.
So that is it. We will see how to provide authentication with OAuth in the next post.
We develop web applications to our customers using python/django/angular.
Contact us at firstname.lastname@example.org