Skip to main content

flask-advanced-auth

PyPI version Python versions License: MIT Tests Coverage

flask-advanced-auth is a production-grade, highly configurable JWT authentication extension for Flask and Flask-SQLAlchemy. It provides multi-rule support (different token lifetimes, secrets, and models for users vs. admins), built-in database token tracking, automatic token revocation (blacklisting), and clean route decorators.


✨ Features

  • 🔑 Multi-Rule Authentication: Define distinct rules for different user tiers (e.g. users, managers, api_clients) with independent secrets, algorithms, and lifetimes.
  • 🛡️ Easy Route Protection: Clean @authenticate(auth_classes=[AuthenticateJWT]) decorator with customizable 401 response and model injection into request.instance.
  • 🔄 Access & Refresh Tokens: Native support for short-lived access tokens and long-lived refresh tokens with convenient refresh_access_token() helper.
  • 🚫 Token Revocation (Blacklisting): Built-in revocation mechanism with database persistence and logout() helper.
  • 📊 Token Tracking: Track issued tokens in the database to detect anomalies, enforce single-session limits, or audit activity.
  • 🔌 Multiple Extraction Strategies: Extract tokens from Authorization: Bearer <token> headers, HTTP cookies, or URL query parameters.
  • ⚡ Pydantic Validation: Strict configuration schema validation powered by Pydantic V2 with flexible aliases.
  • 🧪 Thoroughly Tested: 100% test pass rate with ≥ 88% test coverage.

📦 Installation

pip install flask-advanced-auth

Or install with development dependencies:

pip install flask-advanced-auth[dev]

🚀 Quick Start (5 Minutes)

1. Configure Rules & Bootstrap

from datetime import timedelta
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from flask_advanced_auth import (
    initialize_jwt_authentication,
    authenticate,
    AuthenticateJWT,
    TokenFactory,
    refresh_access_token,
    logout,
)

app = Flask(__name__)
app.config["SECRET_KEY"] = "your-app-secret"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
db = SQLAlchemy(app)

# Define your JWT rules
JWT_RULES = {
    "default": {
        "description": "Standard user access token",
        "secret_key": "your-jwt-secret-key",
        "algorithm": "HS256",
        "access_token_lifetime": timedelta(minutes=15),
        "refresh_token_lifetime": timedelta(days=7),
        "token_header": "Bearer ",
    }
}

# Initialize flask-advanced-auth
initialize_jwt_authentication(
    database_path="app.db",
    rules=JWT_RULES,
)

2. Issue Tokens on Login

@app.route("/api/login", methods=["POST"])
def login():
    username = request.json.get("username")
    
    factory = TokenFactory()
    access_token = factory.generate_token(
        rule_name="default",
        extra_payload={"sub": username},
    )
    refresh_token = factory.generate_refresh_token(
        rule_name="default",
        extra_payload={"sub": username},
    )
    
    return jsonify({
        "access_token": access_token,
        "refresh_token": refresh_token,
    })

3. Protect Routes

@app.route("/api/dashboard")
@authenticate(auth_classes=[AuthenticateJWT], rule_name="default")
def dashboard():
    return jsonify({"message": "Welcome to your protected dashboard!"})

4. Refresh Tokens & Logout

@app.route("/api/refresh", methods=["POST"])
def refresh():
    token = request.json.get("refresh_token")
    new_access_token = refresh_access_token(token, rule_name="default")
    return jsonify({"access_token": new_access_token})

@app.route("/api/logout", methods=["POST"])
def user_logout():
    token = request.headers.get("Authorization", "").replace("Bearer ", "")
    logout(token, rule_name="default")
    return jsonify({"message": "Token revoked successfully."})

⚙️ Configuration Reference

Rules are passed as a dictionary where each key represents a rule name (e.g. "default", "admin"):

Field Type Default Description
description str Required Description of what this token rule is used for.
secret_key str Required Secret signing key for encoding and decoding tokens.
algorithm str Required JWT signing algorithm (e.g. 'HS256', 'RS256').
access_token_lifetime timedelta Required Expiry duration for access tokens.
refresh_token_lifetime timedelta None Expiry duration for refresh tokens.
token_header str 'Bearer ' Expected header prefix in Authorization header.
table bool False Whether to link tokens to a database entity.
table_path str None Dotted import path to model class (e.g. 'myapp.models.User').
track_created bool False Persist issued tokens to the database.
track_created_table_path str None Dotted import path to TrackModel class.
track_created_allow_duplicates bool True Allow multiple active tokens for the same user.
blacklisted bool False Enable token blacklist checks on verification.
blacklisted_table_path str None Dotted import path to BlackListModel class.

🎯 Multi-Token Architecture Guide

You can define multiple token rules tailored for completely different purposes across your application:

import os
from datetime import timedelta

JWT_AUTHENTICATION_RULES = {
    # 1. Stateful Login Token (Tracked in DB + Blacklisted)
    "user_login": {
        "description": "Standard app login",
        "secret_key": os.getenv("JWT_SECRET_USER"),
        "algorithm": "HS256",
        "access_token_lifetime": timedelta(minutes=15),
        "refresh_token_lifetime": timedelta(days=7),
        "track_created": True,
        "track_created_table_path": "myapp.models.TrackedToken",
        "blacklisted": True,
        "blacklisted_table_path": "myapp.models.BlacklistToken",
    },

    # 2. Completely Stateless Email Verification (NO Database needed)
    "email_verification": {
        "description": "Email confirm token for registration",
        "secret_key": os.getenv("JWT_SECRET_EMAIL"),
        "algorithm": "HS256",
        "access_token_lifetime": timedelta(hours=24),
        "table": False,
        "track_created": False,   # Zero DB overhead!
        "blacklisted": False,
    },

    # 3. Live Streaming / WebSocket Token (Extracted via URL Query Parameter)
    "live_stream": {
        "description": "Video stream viewer auth token",
        "secret_key": os.getenv("JWT_SECRET_STREAM"),
        "algorithm": "HS256",
        "access_token_lifetime": timedelta(hours=3),
        "table": False,
        "track_created": False,
    },

    # 4. Password Reset Token (Strict, 10 minutes)
    "password_reset": {
        "description": "One-time password reset",
        "secret_key": os.getenv("JWT_SECRET_RESET"),
        "algorithm": "HS256",
        "access_token_lifetime": timedelta(minutes=10),
        "table": False,
        "track_created": False,
    }
}

🧩 Authentication Strategies

You can choose how tokens are extracted by passing different authentication classes to @authenticate:

from flask_advanced_auth import (
    authenticate,
    HeaderAuthentication,   # Reads Authorization: Bearer <token>
    CookieAuthentication,   # Reads token from HTTP cookies
    QueryParamAuthentication, # Reads ?token=<token>
)

# 1. From Authorization header
@app.route("/api/v1/data")
@authenticate(auth_classes=[HeaderAuthentication])
def api_data():
    return {"status": "ok"}

# 2. From Cookie
@app.route("/web/profile")
@authenticate(auth_classes=[CookieAuthentication])
def web_profile():
    return {"status": "ok"}

# 3. From URL parameter (e.g., SSE or WebSocket connection handshake)
@app.route("/stream")
@authenticate(auth_classes=[QueryParamAuthentication])
def stream():
    return {"status": "connected"}

🗄️ Database Model Mixins

When enabling track_created or blacklisted, use our ready-to-use SQLAlchemy model mixins:

from flask_advanced_auth.models import AbstractTrackModelMixin, AbstractBlackListModelMixin
from myapp.database import db

class TrackedToken(db.Model, AbstractTrackModelMixin):
    __tablename__ = "tracked_tokens"

class BlacklistedToken(db.Model, AbstractBlackListModelMixin):
    __tablename__ = "blacklisted_tokens"

🧪 Running Tests

# Run tests with coverage
pytest -v

# Run single test module
pytest tests/test_decorators.py -v

🤝 Contributing

Contributions are welcome! Please check out CONTRIBUTING.md for setup instructions and guidelines.


💖 Support My Work

If you find my free content and projects helpful, consider supporting me to enable more learning resources for the community. Your contributions will go towards creating new content and maintaining existing projects.

Ways to Support

You can support the project by buying me a coffee:

"Buy Me A Coffee"

Your generosity is greatly appreciated!

Why Support?

By supporting this project, you help ensure the continued availability of free educational content and the development of new projects. Your contribution makes a meaningful impact on the community of learners.

Thank you for your support!


📄 License

This project is licensed under the MIT License — see the LICENSE file for details.

Metadata

Release files for flask-advanced-auth 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flask-advanced-auth 0.1.3
File Size Uploaded Provenance
flask_advanced_auth-0.1.3.tar.gz 28.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for flask-advanced-auth 0.1.3
File Interpreter ABI Platform
flask_advanced_auth-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 53.2 kB

Release files / flask_advanced_auth-0.1.3.tar.gz

Download URL flask_advanced_auth-0.1.3.tar.gz
Size 28.0 kB
Tags Source
SHA-256 checksum
How to use checksums
6d23b79952cc62bca98ea0a8c332b4912d886707835598d840dfc374831cd86e
BLAKE2b-256 checksum
How to use checksums
27310a0025ec19eb04ed45d31c148f0ee6185c9a99f6d57c9dbefb429e99f907
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.8.15

Release files / flask_advanced_auth-0.1.3-py3-none-any.whl

Download URL flask_advanced_auth-0.1.3-py3-none-any.whl
Size 25.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
569231b8baaa064ccbb9dee3f1a45d685838a2602d95f4eb958da682fdb58c8d
BLAKE2b-256 checksum
How to use checksums
f9aac1084d420c32430df85e02a19e11abdbf06031e3f3d922be1600aee33bf6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.8.15

Security for flask-advanced-auth 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page