On software development, quality, security and broken racecars

JSON Web Tokens are a standard method of securing exchanges between two parties (such as web server app and client) that has a number of advantages over other methods of securing exchanges such as cookie-based sessions – enhanced security, less overhead and statelessness to name a few.

In this post, well take a look at using JWT with Flask and Angular 2 and build a simple end-to-end example.

First, let’s start with the server. To provide JWT functionality, I’m using Flask-JWT. This extension enhances Flask by providing a @jwt_required decorator we can attach to any routes we want to protect. The example server code below is pretty similar to the quick start example shown in the Flask-JWT documentation.

The first thing we do is define a simple user model to represent an “identity”:

Python

1

2

3

4

5

6

7

8

9

10

classUser(object):

def__init__(self,id,username,password):

self.id=id

self.username=username

self.password=password

def__str__(self):

return"User(id='%s')"%self.id

user=User(1,'user','password')

In a real world example, you would probably be connecting to a database, directory or some other external service for a user, but for the sake of this simple example, we’ll just hard code a single user.

Next, we declare a couple of functions that Flask-JWT will use to work with our user object:

Python

1

2

3

4

5

6

defauthenticate(username,password):

ifusername==user.username andpassword==user.password:

returnuser

defidentity(payload):

returnuser

The authenticate function is called by Flask-JWT when the login API is invoked with a username and password. This function authenticates the user and returns a user object if successful (or None if not).

The identity function is called by Flask-JWT to look up a user by id. In this case, we simply return the one user.

The SECRET_KEY configuration item is used to digitally-sign the tokens, so in a real-world scenario, set this to some appropriately difficult to guess value (e.g., a random string of characters) and ensure that it is not possible for users to access it. See How to generate good secret keys in the Flask Sessions documentation.

Send CORS Headers

Since the debug instance of the Flask server will be running at “http://localhost:5000” and the Angular 2 front-end will be served at “http://localhost:3000”, we need to have the server send some additional headers to enable Cross-Origin Resource Sharing (CORS). Without these headers, the browser will refuse to load any data from the Flask server because it is running at a different URL due to the same-origin policy.

We could use Flask’s ability to serve static assets to serve the Angular 2 app and avoid having to add the CORS headers, but if we did that, we’d lose automatic rebuild on file changes and other benefits we gain from using node development server.

Finally, let’s declare some resources:

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

@app.route('/unprotected')

defunprotected():

returnjsonify({

'message':'This is an unprotected resource.'

})

@app.route('/protected')

@jwt_required()

defprotected():

returnjsonify({

'message':'This is a protected resource.',

'current_identity':str(current_identity)

})

The first resource is unprotected and can be accessed without a token. The second requires a valid token and return a 403 without it.

The Front-End

Now let’s have a look at at the front-end code. Angular 2 apps require several configuration files, I’m not going to go through each of these as they are well covered elsewhere. All files necessary to run the example are available in the github repo.

In this example, I’m going to use the angular2-jwt library from auth0. While it isn’t absolutely necessary to use a library for JWT support in your Angular app — you could simply treat the token as opaque and generate the headers yourself — the angular2-jwt library provides some nice functionality, including the ability to decode tokens, check their expiration dates, etc. Note that angular2-jwt will work with any JWT backend, an auth0 account is not required.

app.module.ts:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

import{NgModule}from'@angular/core';

import{BrowserModule}from'@angular/platform-browser';

import{HttpModule}from'@angular/http';

import{provideAuth}from'angular2-jwt';

import{AppComponent}from'./app.component';

@NgModule({

imports:[BrowserModule,HttpModule],

providers:[

provideAuth({

headerPrefix:'JWT'

})

],

declarations:[AppComponent],

bootstrap:[AppComponent]

})

exportclassAppModule{}

The main thing we are doing here besides including the augular2-jwt providers is configuring its prefix to “JWT”, which is what Flask-JWT uses as a default.

This is a very simple component that displays a message log. The first thing it does is make a regular unauthenticated request to the unprotected resource. This is just to insure the basics are working: