Implementing Login Authentication with Flask-HTTPAuth and PyJWT in Python

This guide covers using Flask-HTTPAuth and PyJWT to implement token-based login authentication in a Flask application.

Install Dependencies

First, install the required packages:

pip install Flask-HTTPAuth pyjwt passlib

Verify Token Implementation

The following code demonstrates how to verify JSON Web Tokenns (JWT) using Flask-HTTPAuth:

from dependency_injector.wiring import inject, Provide
from flask_httpauth import HTTPTokenAuth
import jwt
from flask import current_app

auth_provider = HTTPTokenAuth(scheme='Bearer')

@auth_provider.verify_token
def verify_token(token):
    try:
        payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
        username = payload['username']
        try:
            user = self.user_repository.get_by_name(username)
        except EntityNotFoundError:
            current_app.logger.error(f'====== Login user not found, name: {username} ======')
            return False
        else:
            return user
    except jwt.exceptions.DecodeError as e:
        current_app.logger.error('====== Decode JWT Failed ======')
        return False
    except jwt.exceptions.ExpiredSignatureError:
        current_app.logger.error('====== JWT Already Expired ======')
        return False

Once auth_provider is defined, any endpoint requiring authentication can simply use the @auth_provider.login_required decorator. The variable name (auth_provider) is customizable – use whatever name you prefer.

When making requests, include Authorization as a header key with the value Bearer <token>. The Bearer scheme is specified when creating auth_provider:

auth_provider = HTTPTokenAuth(scheme='Bearer')

Login Endpoint

The login endpoint verifies the password and returns a JWT. The client then includes this token in subsequent requests.

from flask import Blueprint, jsonify, request, current_app
from dependency_injector.wiring import inject, Provide
from main.containers import Container
from main.security.jwt_filter import auth_provider
import datetime
from passlib.apps import custom_app_context as pwd_context

auth_bp = Blueprint('auth', __name__)

@auth_bp.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    username = data.get('username', None)
    password = data.get('password', None)
    if not username or not password:
        current_app.logger.error('Login failed with missing username or password')
        return jsonify({'error': 'Missing username or password'}), 400
    try:
        user = self.user_repository.get_by_name(username, session)
    except EntityNotFoundError:
        current_app.logger.error(f'====== Login user not found, name: {username} ======')
        return jsonify({'error': 'User does not exist'}), 401
    if pwd_context.verify(password, user.password):
        jwt_token = self._generate_token(user.user_id, username)
        return jsonify({'token': jwt_token}), 200
    else:
        current_app.logger.error(f'{username} login failed.')
        return jsonify({'error': 'Username and password does not match'}), 401

@auth_bp.route('/account', methods=['GET'])
@auth_provider.login_required
def account():
    return auth_provider.current_user().to_response(), 200

def _generate_token(self, user_id, username):
    expire_time = datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=self.access_token_expire_minutes)
    payload = {
        'exp': expire_time,       # expiration time
        'iat': datetime.datetime.now(datetime.UTC),  # issued at
        'sub': user_id,
        'username': username
    }
    token = jwt.encode(payload, 'A05qYNxO/ka9lzjtB5WVJ6li/KHM91fMMT+4Wm6xRBKMivll2kMmR+cJWyEE0bh4PcwI/9LUwwlzZ0pjkFepTg==', algorithm='HS256')
    return token

Important note about decerator order:

The order of decorators matters. The @auth_provider.login_required decorator must appear after the route decorator (@auth_bp.route(...)) to work correctly. Placing it before the route decorator will cause it to be ignored.

@auth_bp.route('/account', methods=['GET'])    # Must be first
@auth_provider.login_required                  # Must be second
def account():
    ...

JWT Expiration

You can customize the expiration time of the JWT according to your applciation's requirements.

Password Hashing

Use Passlib to securely hash passwords:

from passlib.apps import custom_app_context as pwd_context

TEST_USERS_ARRAY = [
    {
        "id": uuid.uuid1().hex,
        "username": "admin",
        "password": pwd_context.encrypt("admin")
    },
    {
        "id": uuid.uuid1().hex,
        "username": "user1",
        "password": pwd_context.encrypt("user1")
    }
]

User Model Example

Below is an example SQLAlchemy model for storing user information:

from flask import jsonify
from sqlalchemy import Column, String
from main.db_access.domain.common_entity import CommonEntity

class User(CommonEntity):
    __tablename__ = "TBL_AA_USER"

    user_id = Column(String, primary_key=True)
    username = Column(String)
    password = Column(String)

    def __init__(self, user_id, username, password):
        self.user_id = user_id
        self.username = username
        self.password = password

    def to_dict(self):
        return {'user_id': self.user_id, 'username': self.username}

    def to_response(self):
        data = self.to_dict()
        response = jsonify(data)
        response.headers['Content-Type'] = 'application/json'
        return response

Tags: Flask JWT Authentication python Flask-HTTPAuth

Posted on Thu, 01 Oct 2026 16:08:36 +0000 by wazza