CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-flask-httpauth

Simple extension that provides Basic and Digest HTTP authentication for Flask routes

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

roles.mddocs/

Role-Based Authorization

Role-based access control system that works across all Flask-HTTPAuth authentication methods. Supports simple roles, multiple roles per user, and complex role hierarchies with flexible authorization callbacks.

Capabilities

User Role Configuration

Register callback functions to define user roles for authorization.

def get_user_roles(self, f):
    """
    Decorator to register user role retrieval callback.
    Available on all authentication classes (HTTPAuth base class).
    
    Parameters:
    - f (function): Callback function(user) -> roles
    
    Returns:
    The decorated function
    
    Usage:
    @auth.get_user_roles
    def get_user_roles(user):
        # Return user roles as string, list, or set
        return user_roles
    """

Role-Based Route Protection

Protect Flask routes with role requirements using the login_required decorator.

def login_required(self, f=None, role=None, optional=None):
    """
    Decorator with role-based authorization support.
    Available on all authentication classes.
    
    Parameters:
    - f (function, optional): Flask route function to protect
    - role (str|list|tuple, optional): Required role(s)
    - optional (bool, optional): Make authentication optional
    
    Returns:
    Decorated function or decorator
    
    Role Matching:
    - Single role: role='admin'
    - Multiple roles (OR): role=['admin', 'moderator']  
    - Multiple roles (AND): role=[['read', 'write']]
    
    Usage:
    @auth.login_required(role='admin')
    def admin_only():
        return "Admin access"
        
    @auth.login_required(role=['admin', 'moderator'])
    def staff_access():
        return "Admin or moderator access"
        
    @auth.login_required(role=[['read', 'write']])
    def full_permissions():
        return "Must have both read AND write roles"
    """

Role Authorization Logic

Internal authorization checking with support for complex role hierarchies.

def authorize(self, role, user, auth):
    """
    Check if user is authorized for the required role(s).
    Internal method called by login_required decorator.
    
    Parameters:
    - role (str|list|tuple|None): Required role(s)
    - user: User object returned by authentication callback
    - auth: Authentication object from request
    
    Returns:
    bool: True if authorized, False otherwise
    
    Authorization Rules:
    - None role: Always authorized (no role required)
    - Single role: User must have exact role
    - List roles: User must have at least one role (OR logic)
    - Nested list: User must have all roles in inner list (AND logic)
    """

Usage Examples

Simple Role System

from flask import Flask
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)
auth = HTTPBasicAuth()

# User database with roles
users = {
    "john": {"password": "hello", "role": "user"},
    "susan": {"password": "bye", "role": "admin"},
    "bob": {"password": "secret", "role": "moderator"}
}

@auth.verify_password
def verify_password(username, password):
    if username in users and users[username]["password"] == password:
        return users[username]

@auth.get_user_roles
def get_user_roles(user):
    return user["role"]

@app.route('/public')
def public():
    return "Public access"

@app.route('/user')
@auth.login_required(role='user')
def user_area():
    return f"User area: {auth.current_user()['role']}"

@app.route('/admin')  
@auth.login_required(role='admin')
def admin_area():
    return f"Admin area: {auth.current_user()['role']}"

Multiple Roles Per User

from flask import Flask
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)
auth = HTTPBasicAuth()

# Users with multiple roles
users = {
    "john": {"password": "hello", "roles": ["user"]},
    "susan": {"password": "bye", "roles": ["user", "admin"]},
    "bob": {"password": "secret", "roles": ["user", "moderator"]},
    "alice": {"password": "key", "roles": ["admin", "moderator"]}
}

@auth.verify_password
def verify_password(username, password):
    if username in users and users[username]["password"] == password:
        return users[username]

@auth.get_user_roles
def get_user_roles(user):
    return user["roles"]

@app.route('/user')
@auth.login_required(role='user')
def user_area():
    return "All authenticated users"

@app.route('/staff')
@auth.login_required(role=['admin', 'moderator'])
def staff_area():
    return "Admin OR moderator access"

@app.route('/admin')
@auth.login_required(role='admin')
def admin_area():
    return "Admin only"

Complex Role Hierarchies

from flask import Flask
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)
auth = HTTPBasicAuth()

# Complex role system with permissions
users = {
    "john": {
        "password": "hello", 
        "roles": ["read", "user"]
    },
    "susan": {
        "password": "bye", 
        "roles": ["read", "write", "admin", "user"]
    },
    "bob": {
        "password": "secret", 
        "roles": ["read", "write", "user"]
    }
}

@auth.verify_password
def verify_password(username, password):
    if username in users and users[username]["password"] == password:
        return users[username]

@auth.get_user_roles
def get_user_roles(user):
    return user["roles"]

@app.route('/read')
@auth.login_required(role='read')
def read_data():
    return "Read access granted"

@app.route('/write')
@auth.login_required(role='write')
def write_data():
    return "Write access granted"

@app.route('/edit')
@auth.login_required(role=[['read', 'write']])
def edit_data():
    return "Edit requires BOTH read AND write permissions"

@app.route('/admin')
@auth.login_required(role='admin')
def admin_panel():
    return "Admin panel access"

@app.route('/superuser')
@auth.login_required(role=[['admin', 'write']])
def superuser_area():
    return "Requires BOTH admin AND write permissions"

Database-Driven Roles

from flask import Flask
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)
auth = HTTPBasicAuth()

# Simulate database lookup
class UserRoleManager:
    def __init__(self):
        # In real apps, this would be a database
        self.users = {
            "john": {"password": "hello", "id": 1},
            "susan": {"password": "bye", "id": 2}
        }
        
        self.user_roles = {
            1: ["user", "customer"],
            2: ["user", "admin", "customer", "staff"]
        }
    
    def get_user(self, username, password):
        user = self.users.get(username)
        if user and user["password"] == password:
            return user
        return None
    
    def get_roles(self, user_id):
        return self.user_roles.get(user_id, [])

role_manager = UserRoleManager()

@auth.verify_password
def verify_password(username, password):
    return role_manager.get_user(username, password)

@auth.get_user_roles
def get_user_roles(user):
    return role_manager.get_roles(user["id"])

@app.route('/customer')
@auth.login_required(role='customer')
def customer_area():
    return "Customer area"

@app.route('/staff')
@auth.login_required(role='staff')
def staff_area():
    return "Staff area"

Token Authentication with Roles

from flask import Flask
from flask_httpauth import HTTPTokenAuth
import jwt

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
auth = HTTPTokenAuth('Bearer')

@auth.verify_token
def verify_token(token):
    try:
        # Decode JWT token with role information
        data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
        return {
            "username": data["username"],
            "roles": data.get("roles", [])
        }
    except jwt.InvalidTokenError:
        return None

@auth.get_user_roles
def get_user_roles(user):
    return user["roles"]

@app.route('/api/user')
@auth.login_required(role='user')
def user_api():
    return {"message": f"User API: {auth.current_user()['username']}"}

@app.route('/api/admin')
@auth.login_required(role='admin')
def admin_api():
    return {"message": f"Admin API: {auth.current_user()['username']}"}

# Token generation example
def generate_token(username, roles):
    payload = {
        "username": username,
        "roles": roles,
        "exp": datetime.utcnow() + timedelta(hours=1)
    }
    return jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')

Role Matching Logic

Flask-HTTPAuth supports flexible role matching:

Single Role

@auth.login_required(role='admin')
# User must have exactly 'admin' role

Multiple Roles (OR Logic)

@auth.login_required(role=['admin', 'moderator'])
# User must have 'admin' OR 'moderator' role

Multiple Roles (AND Logic)

@auth.login_required(role=[['read', 'write']])
# User must have BOTH 'read' AND 'write' roles

Complex Combinations

@auth.login_required(role=[['admin', 'write'], 'superuser'])
# User must have (admin AND write) OR superuser

Error Handling

Role-based authorization generates appropriate HTTP status codes:

  • 401 Unauthorized: Authentication failed or missing
  • 403 Forbidden: Authentication succeeded but insufficient role permissions
  • Automatic Role Check: Performed after successful authentication
  • Custom Error Handlers: Can be implemented using the error_handler decorator

The role authorization system integrates seamlessly with all Flask-HTTPAuth authentication methods and provides detailed error information for debugging role-based access issues.

Install with Tessl CLI

npx tessl i tessl/pypi-flask-httpauth

docs

basic-auth.md

digest-auth.md

index.md

multi-auth.md

roles.md

token-auth.md

tile.json