Python - 301 - Flask
  • 00 - Appealing API's
  • 01- A Smooth Start
  • 02 - Chief Configuration
  • 03 - Example Endpoint and an Adornable App
  • 04 - Modeling the Models
  • 05 - Scheming Schemas
  • 06 - Making Migrations
  • 07 - Uniformed Users
  • 08 - Alarming Authentication
  • 09 - Account Actions
  • 10 - Postman Prevalence and Examining Endpoints
  • 11 - Blog Post Blogging
Powered by GitBook
On this page

Was this helpful?

08 - Alarming Authentication

In this module we will define our own way of decoding and decoding tokens in an Authentication class

Authentication is pretty straightforward. We want to make sure we protect our resources from unauthorized users. This is so we know who and what is using our API. Every method that requires authentication needs what is called a Json Web Token. These are encrypted strings of data that contain the necessary details to verify a user stored in the database

For our authentication, we will be using only one class that contains functions to abstract the jwt module, and a decorator that will act as a gatekeeper

Add the following code to your shared/authentication file

import jwt
import os
import datetime

from functools import wraps

from flask import json, Response, request, g
from ..models.user import UserModel


class Auth:
    @staticmethod
    def auth_required(f):
        @wraps(f)
        def auth_wrapper(*args, **kwargs):
            if 'api-token' not in request.headers:
                return Response(
                    mimetype='application/json',
                    response=json.dumps({
                        'error': 'Authentication token not provided'
                    }),
                    status=400
                )
            token = request.headers.get('api-token')
            data = Auth.decode_token(token)
            if data['error']:
                return Response(
                    mimetype='application/json',
                    response=json.dumps(data['error']),
                    status=400
                )

            user_id = data['data']['user_id']
            check_user = UserModel.get_one_user(user_id)

            if not check_user:
                return Response(
                    mimetype='application/json',
                    response=json.dumps({
                        'error': 'user does not exist, bad token'
                    }),
                    status=400
                )

            g.user = {'id': user_id}
            return f(*args, **kwargs)
        return auth_wrapper


    @staticmethod
    def decode_token(token):
        re = {'data': {}, 'error': {}}
        try:
            payload = jwt.decode(token, os.getenv('JWT_SECRET_KEY'))
            re['data'] = {'user_id': payload['sub']}
            return re
        except jwt.ExpiredSignatureError as el:
            re['error'] = {'message': 'invalid token'}
            return re

    @staticmethod
    def generate_token(user_id):
        try:
            payload = {
                'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1),
                'iat': datetime.datetime.utcnow(),
                'sub': user_id
            }
            return jwt.encode(
                payload,
                os.getenv('JWT_SECRET_KEY'),
                'HS256'
            ).decode('utf-8')
        except Exception as e:
            return Response(
                mimetype='application/json',
                response=json.dumps({'error': 'error generating user token'}),
                status=400
            )

Let's take a look at these functions one at a time

auth required - This is the decorator. We will use this on the views to verify that if a token was passed, it's the correct token. This decorator will use the next method in the class

decode_token - This static method is responsible for sending tokens to the jwt module and also check if the token has expired or not. This method will return the data back to the decorator to finish authentication

generate_token - This method will take in a user id and hash out a payload for the token. This is information about the token including expiration, issued at, and the subscriber. Then the method will return an encoded token or present an error if anything happened incorrectly

Previous07 - Uniformed UsersNext09 - Account Actions

Last updated 6 years ago

Was this helpful?