Simple extension that provides Basic and Digest HTTP authentication for Flask routes
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
HTTP Digest authentication implementation providing enhanced security over Basic auth through challenge-response mechanisms. Digest auth never transmits passwords in clear text, instead using MD5 hashing with nonce values to prevent replay attacks.
Creates an HTTP Digest authentication handler with configurable algorithms, quality of protection, and nonce/opaque value management.
class HTTPDigestAuth(HTTPAuth):
def __init__(self, scheme=None, realm=None, use_ha1_pw=False, qop='auth', algorithm='MD5'):
"""
Initialize Digest authentication handler.
Parameters:
- scheme (str, optional): Authentication scheme, defaults to 'Digest'
- realm (str, optional): Authentication realm, defaults to 'Authentication Required'
- use_ha1_pw (bool): Use HA1 hashed passwords instead of plain passwords
- qop (str|list): Quality of protection ('auth' or list of QOP values)
- algorithm (str): Hash algorithm ('MD5' or 'MD5-Sess')
"""Configure nonce generation and verification for preventing replay attacks.
def generate_nonce(self, f):
"""
Decorator to register nonce generation callback.
Parameters:
- f (function): Callback function() -> nonce_string
Returns:
The decorated function
Usage:
@auth.generate_nonce
def generate_nonce():
return secrets.token_hex(16)
"""
def verify_nonce(self, f):
"""
Decorator to register nonce verification callback.
Parameters:
- f (function): Callback function(nonce) -> bool
Returns:
The decorated function
Usage:
@auth.verify_nonce
def verify_nonce(nonce):
return nonce in valid_nonces
"""
def get_nonce(self):
"""
Generate a new nonce value.
Returns:
str: Generated nonce string
"""Configure opaque value generation and verification for additional security.
def generate_opaque(self, f):
"""
Decorator to register opaque value generation callback.
Parameters:
- f (function): Callback function() -> opaque_string
Returns:
The decorated function
"""
def verify_opaque(self, f):
"""
Decorator to register opaque value verification callback.
Parameters:
- f (function): Callback function(opaque) -> bool
Returns:
The decorated function
"""
def get_opaque(self):
"""
Generate a new opaque value.
Returns:
str: Generated opaque string
"""Handle password retrieval and HA1 hash generation for digest authentication.
def generate_ha1(self, username, password):
"""
Generate HA1 hash for digest authentication.
Parameters:
- username (str): Username
- password (str): Plain text password
Returns:
str: MD5 hash of username:realm:password
"""Protect Flask routes with Digest authentication using the login_required decorator.
def login_required(self, f=None, role=None, optional=None):
"""
Decorator to require digest authentication for Flask routes.
Parameters:
- f (function, optional): Flask route function to protect
- role (str|list, optional): Required user role(s)
- optional (bool, optional): Make authentication optional
Returns:
Decorated function or decorator
"""Generate proper WWW-Authenticate headers for digest authentication challenges.
def authenticate_header(self):
"""
Generate WWW-Authenticate header for digest authentication.
Returns:
str: Properly formatted digest authentication challenge header
"""from flask import Flask
from flask_httpauth import HTTPDigestAuth
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key here'
auth = HTTPDigestAuth()
users = {
"john": "hello",
"susan": "bye"
}
@auth.get_password
def get_pw(username):
if username in users:
return users.get(username)
return None
@app.route('/')
@auth.login_required
def index():
return f"Hello, {auth.username()}"
if __name__ == '__main__':
app.run()from flask import Flask, session
from flask_httpauth import HTTPDigestAuth
import secrets
import time
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key here'
auth = HTTPDigestAuth()
# Store nonces with timestamps
nonces = {}
@auth.generate_nonce
def generate_nonce():
nonce = secrets.token_hex(16)
nonces[nonce] = time.time()
return nonce
@auth.verify_nonce
def verify_nonce(nonce):
if nonce in nonces:
# Check if nonce is still valid (not expired)
if time.time() - nonces[nonce] < 300: # 5 minutes
return True
else:
del nonces[nonce]
return Falsefrom flask import Flask
from flask_httpauth import HTTPDigestAuth
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key here'
auth = HTTPDigestAuth(use_ha1_pw=True)
# Pre-computed HA1 hashes: MD5(username:realm:password)
users_ha1 = {
"john": "b4bbcabacfa91dcc1f5e1e47e3e6bdbe", # john:Authentication Required:hello
"susan": "1f3870be274f6c49b3e31a0c6728957f" # susan:Authentication Required:bye
}
@auth.get_password
def get_password_ha1(username):
if username in users_ha1:
return users_ha1[username]
return None
@app.route('/')
@auth.login_required
def index():
return f"Hello, {auth.username()}"from flask import Flask
from flask_httpauth import HTTPDigestAuth
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key here'
# Configure digest auth with MD5-Sess algorithm
auth = HTTPDigestAuth(qop=['auth', 'auth-int'], algorithm='MD5-Sess')
users = {
"john": "hello",
"susan": "bye"
}
@auth.get_password
def get_pw(username):
return users.get(username)
@app.route('/')
@auth.login_required
def index():
return f"Hello, {auth.username()}"Digest authentication handles various error conditions:
The digest implementation automatically manages the challenge-response cycle and validates all digest authentication parameters according to RFC 2617 specifications.
Install with Tessl CLI
npx tessl i tessl/pypi-flask-httpauth