Angular API Calls with Django: Authentication with JWT

Curious about how to make API calls with Angular 6 and the HttpClient service? This tutorial will show you some techniques for building a decoupled micro-blogging application using Angular 6 and the Django Rest Framework (DRF). Along the way, we will learn the following:

  • How to set up the back end of the app using Django and the Django Rest Framework API
  • Creating a simple Angular 6 single-page app which can query the API
  • Authenticating users with JSON Web Tokens (JWT)

Ready? Let's get started!

Try this at home

The source code for this tutorial can be found on GitHub at https://github.com/kdechant/angular-django-example.

The example code requires Python 3 (Django 2.x requires Python 3.4 or higher) and uses a SQLite database, so install should be easy and painless.

Background info

My previous tutorial will give you a basic understanding of how to make API calls using Angular.

If you're new to Django and DRF, you can find some useful tutorials at the Django project and the Django Rest Framework site. This example will build upon the basic knowledge from those tutorials.

Some knowledge of pip and Python Virtual Environments will also be useful here. Be aware that we're using classic virtualenv here and not the newer pipenv yet.

Technology selection

The demo shown here uses the following technology:

  • Angular 6.1 - The latest as of the time of this writing
  • RxJS 6.0 - This is the version included with Angular 6.0. All API calls in this tutorial use the newer RxJS syntax introduced with this version. See my previous post about upgrading from RxJS 5.5 here.
  • Angular CLI v6.x
  • Django 2.1 - The current release of Django
  • Django Rest Framework - The standard suite for generating a REST API in Django
  • Python 3.5 or higher - Django 2.x requires Python 3 and no longer supports Python 2.7
  • Node 8.x or higher

Why these platforms? Angular, because it's a full-featured front-end framework that has tremendous popularity. Django and Django Rest Framework, to provide the ORM and API layer. Python is growing in popularity and is an enjoyable language to develop applications.

The Django app

The Django app is the back end of our decoupled application. It serves the API endpoints and it also renders the HTML container for the Angular front end app.

We will dive more deeply into DRF and its models, serializers, and viewsets in a later part of this tutorial. For now, we have a simple Django project with Django Rest Framework and the Django Rest Framework JWT packages installed.

pip install Django
pip install djangorestframework djangorestframework-jwt.

What these do:

  • the DJango package is the basic framework itself
  • djangorestframework is the core of DRF and provides the means to build API endpoints
  • djangorestframework-jwt is an extension to DRF which provides an authentication layer using JSON Web Tokens

The vanilla install of Django provides a basic settings file for the application. To activate DRF and the JWT extension, we need to add DRF to our installed apps, and configure its settings:

angular_django_example/settings.py:

INSTALLED_APPS = [
    ...
    'rest_framework',
]
 
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

By default, DRF allows Basic and Session authentication. The DEFAULT_AUTHENTICATION_CLASSES setting adds a third authentication mechanism, the JWT.

How do these work?

  • Basic Auth - a username and password are passed with each API request. This provides only a minimum level of security and user credentials are visible in the URLs
  • Session Auth - requires the user to log in through the server-side application before using the API. This is more secure than Basic Auth but is not convenient for working with single-page apps in a framework like Angular.
  • JSON Web Tokens are an industry standard mechanism for generating a token which can be passed in the HTTP headers of each request, authenticating the user. This is the mechanism we will use for authentication.

In addition to the Rest Framework configuration, the JWT package also has its own configuration settings. We will update two settings in particular for our app.

angular_django_example/settings.py

JWT_AUTH = {
    'JWT_ALLOW_REFRESH': True,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=3600),
}

JWT tokens have a life span, after which they are no longer valid. The default is only 5 minutes, but we can set it to a longer time (say, 1 hour) using the JWT_EXPIRATION_DELTA setting. The JWT_ALLOW_REFRESH setting enables a feature of DRF-JWT where an application can request a refreshed token with a new expiration date.

URLs

In addition to the settings, we need to add a few URLs to our API:

angular_django_example/urls.py:

from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token
 
urlpatterns = [
    ... other patterns here ...
    path(r'api-token-auth/', obtain_jwt_token),
    path(r'api-token-refresh/', refresh_jwt_token),
]

These endpoints provide us with a means to authenticate via the API and to request a new token.

The Microblog app

Now that our application-wide settings are configured, we can create the Django app and the Angular app within it.

From the terminal, we can run python manage.py startapp microblog to create our new Microblog app. This gives us an empty Django app with the usual views.py, models.py, urls.py, and so on.

We now need to create a simple View and a template which will serve the single-page app.

microblog/views.py:

from django.shortcuts import render
 
def index(request, path=''):
    """
    The home page. This renders the container for the single-page app.
    """
    return render(request, 'index.html')

In Django fashion, we will use two template files, base.html, providing the outer HTML shell, and index.html, providing the content of the index page itself.

microblog/templates/base.html:

{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Angular, Django Rest Framework, and JWT token demo</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
</head>
<body>
  <div class="container">
    {% block heading %}
      <h1>Angular, Django Rest Framework, and JWT demo</h1>
    {% endblock %}
 
    {% block content %}{% endblock %}
  </div>
</body>
</html>

microblog/templates/index.html:

{% extends "base.html" %}
{% load staticfiles %}
 
{% block content %}
  <p>This is a mini-blog application using a back-end built on Django 2.0 and Django Rest Framework. It illustrates how to create and send JSON Web Token authentication headers with the HTTP requests.</p>
 
  <app-root>Loading the app...</app-root>
 
  <script type="text/javascript" src="{% static 'front-end/runtime.js' %}"></script>
  <script type="text/javascript" src="{% static 'front-end/polyfills.js' %}"></script>
  <script type="text/javascript" src="{% static 'front-end/styles.js' %}"></script>
  <script type="text/javascript" src="{% static 'front-end/vendor.js' %}"></script>
  <script type="text/javascript" src="{% static 'front-end/main.js' %}"></script>
 
{% endblock %}

The <script> tags in index.html will load the compiled JavaScript files generated by webpack. We'll need to change a setting in angular.json to make this work, which we'll see momentarily.

For the first part of this tutorial, we are using only built-in models (like django.contrib.auth.models.User) and the Views that are provided by DRF and the JWT extension. In Part 2, we will delve into creating the rest of our micro-blogging application. There, you will see custom models, serializers, and views.

The Angular App

To install an Angular app within a Django project, we just place the TypeScript source code inside of our "microblog" Django app.

Back to Top