DEV Community

Israel Aminu
Israel Aminu

Posted on

Using JSON Web Token(JWT) with Python

Authorization and security remain a key feature when building Web API for users or for an organization and knowing the amount of information you want to make accessible. Most web apps take security measures to make sure the user(s) information is safe and secure.

What is a JSON Web Token(JWT)?
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between a client and a server as a JSON object. This information can be verified and trusted because it is digitally signed. - jwt.io

How JWT Works?
A server generates a token that certifies the user identity and sends it to the client. The client will send the token back to the server for every subsequent request to an endpoint to access a particular service, the client can send the token via a header or a query parameter so the server then knows the request comes from a particular identity or user. Also, we can set the validity of the token by setting an elapsed time for the token to expire. Whereafter the user is authenticated when we perform API requests either to a REST API.
Alt Text
To read more about JWT, you can check here

Using JWT in python

pip install pyjwt

Example Usage

>>> import jwt
>>> secretKey = 'secret'
>>> encoded_jwt = jwt.encode({'some': 'payload'},secretKey, algorithm='HS256')
>>> encoded_jwt
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'

>>> jwt.decode(encoded_jwt,secretKey, algorithms=['HS256'])
{'some': 'payload'}
Enter fullscreen mode Exit fullscreen mode

What just happened is simply encoding the information present in that JSON as a token using a secret key and decrypting it to access the information. I'll show you a little demo of how I implemented a JSON web token using flask, you can also apply the same logic to Django also.

My Working Directory.

.
├── app.py
├── authenticate.py

Enter fullscreen mode Exit fullscreen mode

authenticate.py

This is the python file I use to accept and verify tokens and then use it as a python decorator in my flask app.

import json
import jwt
from flask import Flask, request

flask_app = Flask(__name__)

SECRET_KEY = "hkBxrbZ9Td4QEwgRewV6gZSVH4q78vBia4GBYuqd09SsiMsIjH"

def token_required(something):
    def wrap():
        try:
            token_passed = request.headers['TOKEN']
            if request.headers['TOKEN'] != '' and request.headers['TOKEN'] != None:
                try:
                    data = jwt.decode(token_passed,SECRET_KEY, algorithms=['HS256'])
                    return something()
                except jwt.exceptions.ExpiredSignatureError:
                    return_data = {
                        "error": "1",
                        "message": "Token has expired"
                        }
                    return flask_app.response_class(response=json.dumps(return_data), mimetype='application/json'),401
                except:
                    return_data = {
                        "error": "1",
                        "message": "Invalid Token"
                    }
                    return flask_app.response_class(response=json.dumps(return_data), mimetype='application/json'),401
            else:
                return_data = {
                    "error" : "2",
                    "message" : "Token required",
                }
                return flask_app.response_class(response=json.dumps(return_data), mimetype='application/json'),401
        except Exception as e:
            return_data = {
                "error" : "3",
                "message" : "An error occured"
                }
            return flask_app.response_class(response=json.dumps(return_data), mimetype='application/json'),500

    return wrap


#
Enter fullscreen mode Exit fullscreen mode

I used the request.headers to accept the token from the client using the "TOKEN" header variable, then I try to decrypt the token, if the token is valid, the client will have access to that endpoint. If the token has expired or the client decides to use and old token it will return the "Token has Expired" response and throw a 401, also if the client tries to create any form of token that's not correct he'll get an "Invalid token" response. If no token is passed to access a particular endpoint in my web app it will ask for a token to access the endpoint. And if there's any other issue it will return "An error occurred" response.

app.py

import json
import jwt
import datetime
from authenticate import token_required #The token verification script
from flask import Flask, request

SECRET_KEY = "hkBxrbZ9Td4QEwgRewV6gZSVH4q78vBia4GBYuqd09SsiMsIjH"

flask_app = Flask(__name__)

@flask_app.route('/loginEndpoint', methods=['POST'])
def loginFunction():
    userName = request.form.get('username')
    passWord = request.form.get('password')
    #Generate token
    timeLimit= datetime.datetime.utcnow() + datetime.timedelta(minutes=30) #set limit for user
    payload = {"user_id": userName,"exp":timeLimit}
    token = jwt.encode(payload,SECRET_KEY)
    return_data = {
        "error": "0",
        "message": "Successful",
        "token": token.decode("UTF-8"),
        "Elapse_time": f"{timeLimit}"
        }
    return flask_app.response_class(response=json.dumps(return_data), mimetype='application/json')


@flask_app.route('/anEndpoint',methods=['POST'])
@token_required #Verify token decorator
def aWebService():
    return_data = {
        "error": "0",
        "message": "You Are verified"
        }
    return flask_app.response_class(response=json.dumps(return_data), mimetype='application/json')

if __name__ == "__main__":
    flask_app.run(port=8080, debug=True)
Enter fullscreen mode Exit fullscreen mode

In the python file I imported the necessary libraries and also the python script where I use to authenticate client tokens.

The flask app contains a simple login function which requests a username and password, then a token is generated which stores the username to the token and also the token also expires 30 mins from when it is generated, after that the token will no longer be valid. When the token is generated it will be sent as a response to the client, which the client can then use to access other endpoints that require a token

To access the second endpoint created above, the user needs to pass in the token generated hence the decorator @token_required above the function, if the token is correct the client will be able to access the services in that function and if the token is wrong or expired the client cannot have access to that service.

And there you have it, that's how you can simply add a JSON web token(JWT) to your REST API python project to authenticate your users or client.

Discussion (1)

Collapse
spencerdavis2000 profile image
Spencer Davis

Great article thank you