CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-flask-security

Quickly add security features to your Flask application.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

utilities.mddocs/

Utility Functions

Helper functions for URLs, tokens, validation, communication, and other common security operations that support Flask-Security's core functionality.

Capabilities

URL and Navigation Utilities

Functions for generating security-related URLs and handling navigation within Flask-Security.

def url_for_security(endpoint, **values):
    """
    Generate URLs for Flask-Security endpoints.
    
    Parameters:
    - endpoint: Security endpoint name (e.g., 'login', 'register', 'reset_password')
    - values: Additional URL parameters and query arguments
    
    Returns:
    Generated URL string for the security endpoint
    """

def get_url(endpoint_or_url, qparams=None, **values):
    """
    Generate URLs with query parameters.
    
    Parameters:
    - endpoint_or_url: Flask endpoint name or absolute URL
    - qparams: Dictionary of query parameters to append
    - values: Additional URL generation values
    
    Returns:
    Complete URL with query parameters
    """

def transform_url(url, qparams=None, **params):
    """
    Transform URLs with custom logic and parameters.
    
    Parameters:
    - url: Base URL to transform
    - qparams: Query parameters to add or modify
    - params: Additional transformation parameters
    
    Returns:
    Transformed URL string
    """

def get_post_login_redirect():
    """
    Get redirect URL after successful login.
    
    Returns:
    URL string for post-login redirect, considering 'next' parameter
    """

def get_logout_redirect():
    """
    Get redirect URL after logout.
    
    Returns:  
    URL string for post-logout redirect
    """

Token and Security Utilities

Functions for generating, validating, and managing security tokens and cryptographic operations.

def get_hmac(password):
    """
    Generate HMAC for token security and password operations.
    
    Parameters:
    - password: Password or data to generate HMAC for
    
    Returns:
    HMAC digest string
    """

def check_and_get_token_status(token, serializer, max_age=None):
    """
    Validate token status and return token information.
    
    Parameters:
    - token: Token string to validate
    - serializer: Token serializer instance  
    - max_age: Maximum token age in seconds (optional)
    
    Returns:
    Tuple of (is_expired: bool, is_invalid: bool, token_data: dict)
    """

def generate_token(data, salt=None):
    """
    Generate secure token from data.
    
    Parameters:
    - data: Data to encode in token
    - salt: Salt for token generation (optional)
    
    Returns:
    Generated token string
    """

def verify_token(token, salt=None, max_age=None):
    """
    Verify and decode token data.
    
    Parameters:
    - token: Token string to verify
    - salt: Salt used for token generation (optional)
    - max_age: Maximum acceptable token age in seconds
    
    Returns:
    Decoded token data if valid, None if invalid or expired
    """

Password Validation Utilities

Functions for validating password strength, complexity, and security requirements.

def password_length_validator(password, min_length=None, max_length=None):
    """
    Validate password length requirements.
    
    Parameters:
    - password: Password string to validate
    - min_length: Minimum required length (default: from config)
    - max_length: Maximum allowed length (default: from config)
    
    Returns:
    True if valid, raises ValidationError if invalid
    """

def password_complexity_validator(password, **requirements):
    """
    Validate password complexity requirements.
    
    Parameters:
    - password: Password string to validate
    - requirements: Complexity requirements dict (uppercase, lowercase, digits, symbols)
    
    Returns:
    True if valid, raises ValidationError if invalid
    """

def password_breached_validator(password, check_breach_count=True):
    """
    Check password against known breach databases.
    
    Parameters:
    - password: Password string to check
    - check_breach_count: Whether to check breach count threshold
    
    Returns:
    True if password is safe, raises ValidationError if breached
    """

def pwned(password, user_agent=None, request_timeout=1.0):
    """
    Check if password appears in HaveIBeenPwned breach database.
    
    Parameters:
    - password: Password string to check
    - user_agent: Custom User-Agent for API requests  
    - request_timeout: Timeout for API request in seconds
    
    Returns:
    Number of times password appears in breaches, 0 if safe
    """

Communication Utilities

Functions for sending emails, SMS messages, and other forms of communication.

def send_mail(subject, recipient, template, **context):
    """
    Send email utility function with template rendering.
    
    Parameters:
    - subject: Email subject line
    - recipient: Recipient email address
    - template: Template name for email body
    - context: Template context variables
    
    Returns:
    True if email sent successfully, False otherwise
    """

class MailUtil:
    """
    Email handling and template rendering utility class.
    """
    
    def __init__(self, app=None):
        """
        Initialize mail utility.
        
        Parameters:
        - app: Flask application instance (optional)
        """
    
    def init_app(self, app):
        """
        Initialize mail utility with Flask app.
        
        Parameters:
        - app: Flask application instance
        """
    
    def send_mail(self, template, subject, recipient, sender=None, **kwargs):
        """
        Send templated email.
        
        Parameters:
        - template: Email template name
        - subject: Email subject
        - recipient: Recipient email address
        - sender: Sender email address (optional)
        - kwargs: Template context variables
        
        Returns:
        True if sent successfully, False otherwise
        """
    
    def render_template(self, template, **kwargs):
        """
        Render email template with context.
        
        Parameters:
        - template: Template name to render
        - kwargs: Template context variables
        
        Returns:
        Rendered template string
        """

class EmailValidateException(Exception):
    """Exception raised for email validation errors."""
    pass

SMS Communication Classes

Classes and factory for SMS message sending with multiple provider support.

class SmsSenderBaseClass:
    """
    Abstract base class for SMS senders.
    """
    
    def __init__(self, **kwargs):
        """
        Initialize SMS sender.
        
        Parameters:
        - kwargs: Provider-specific configuration
        """
    
    def send_sms(self, from_number, to_number, msg):
        """
        Send SMS message.
        
        Parameters:
        - from_number: Sender phone number
        - to_number: Recipient phone number  
        - msg: Message content
        
        Returns:
        True if sent successfully, False otherwise
        """

class SmsSenderFactory:
    """
    Factory for creating SMS sender instances.
    """
    
    @staticmethod
    def createSender(name, **kwargs):
        """
        Create SMS sender instance by name.
        
        Parameters:
        - name: SMS service name ('Dummy', 'Twilio', etc.)
        - kwargs: Service-specific configuration
        
        Returns:
        SMS sender instance
        """

class DummySmsSender(SmsSenderBaseClass):
    """
    Dummy SMS sender implementation for testing and development.
    """
    
    def send_sms(self, from_number, to_number, msg):
        """Send SMS (dummy implementation that logs message)."""
        print(f"SMS to {to_number}: {msg}")
        return True

Time and Request Utilities

Utility functions for handling time operations and request context management.

def naive_utcnow():
    """
    Get current UTC time as naive datetime.
    
    Returns:
    Datetime object representing current UTC time without timezone info
    """

def get_request_attr(name):
    """
    Get attribute from current request context.
    
    Parameters:
    - name: Attribute name to retrieve from request
    
    Returns:
    Attribute value if found, None otherwise
    """

def get_request_attr_or_default(name, default=None):
    """
    Get request attribute with default fallback.
    
    Parameters:
    - name: Attribute name to retrieve
    - default: Default value if attribute not found
    
    Returns:
    Attribute value or default
    """

Specialized Utility Classes

Utility classes for managing specific Flask-Security features and operations.

class PasswordUtil:
    """
    Password management and policy utility class.
    """
    
    def __init__(self, app=None):
        """Initialize password utility."""
    
    def init_app(self, app):
        """Initialize with Flask app."""
    
    def hash_password(self, password):
        """
        Hash password using configured algorithm.
        
        Parameters:
        - password: Plain text password to hash
        
        Returns:
        Hashed password string
        """
    
    def verify_password(self, password, password_hash):
        """
        Verify password against hash.
        
        Parameters:
        - password: Plain text password
        - password_hash: Stored password hash
        
        Returns:
        True if password matches, False otherwise
        """
    
    def validate_password(self, password):
        """
        Validate password against configured policies.
        
        Parameters:
        - password: Password to validate
        
        Returns:
        True if valid, raises ValidationError if invalid
        """

class PhoneUtil:
    """
    Phone number validation and formatting utility class.
    """
    
    def __init__(self, app=None):
        """Initialize phone utility."""
    
    def init_app(self, app):
        """Initialize with Flask app."""
    
    def validate_phone_number(self, phone_number):
        """
        Validate phone number format.
        
        Parameters:
        - phone_number: Phone number string to validate
        
        Returns:
        True if valid, False otherwise
        """
    
    def normalize_phone_number(self, phone_number):
        """
        Normalize phone number to standard format.
        
        Parameters:
        - phone_number: Phone number to normalize
        
        Returns:
        Normalized phone number string
        """

class UsernameUtil:
    """
    Username validation and management utility class.
    """
    
    def __init__(self, app=None):
        """Initialize username utility."""
    
    def init_app(self, app):
        """Initialize with Flask app."""
    
    def validate_username(self, username):
        """
        Validate username format and requirements.
        
        Parameters:
        - username: Username to validate
        
        Returns:
        True if valid, raises ValidationError if invalid
        """
    
    def normalize_username(self, username):
        """
        Normalize username format.
        
        Parameters:
        - username: Username to normalize
        
        Returns:
        Normalized username string
        """

TOTP Utility Class

Time-based One-Time Password generation and validation for two-factor authentication.

class Totp:
    """
    Time-based One-Time Password generation and validation utility class.
    """
    
    def __init__(self, secret=None, issuer=None):
        """
        Initialize TOTP utility.
        
        Parameters:
        - secret: Base32-encoded secret key (optional, generates if not provided)
        - issuer: Issuer name for TOTP (optional)
        """
    
    def generate_password(self, counter=None):
        """
        Generate TOTP password for current time window.
        
        Parameters:
        - counter: Time counter (optional, uses current time if not provided)
        
        Returns:
        6-digit TOTP code as string
        """
    
    def verify(self, token, window=0):
        """
        Verify TOTP token against current time.
        
        Parameters:
        - token: TOTP token string to verify
        - window: Number of time windows to check (default: 0)
        
        Returns:
        True if token is valid, False otherwise
        """
    
    def generate_qr_code(self, name, issuer=None):
        """
        Generate QR code for TOTP secret.
        
        Parameters:
        - name: Account name for QR code
        - issuer: Issuer name (optional)
        
        Returns:
        QR code image data as base64 string
        """
    
    @property
    def secret(self):
        """
        Get TOTP secret key.
        
        Returns:
        Base32-encoded secret string
        """
    
    @property
    def provisioning_uri(self):
        """
        Get provisioning URI for authenticator apps.
        
        Returns:
        otpauth:// URI string
        """

Usage Examples

URL Generation and Navigation

from flask_security import url_for_security, get_url

@app.route('/custom-login')
def custom_login_redirect():
    """Redirect to Flask-Security login page."""
    login_url = url_for_security('login', next='/dashboard')
    return redirect(login_url)

@app.route('/user-profile')
@login_required
def user_profile():
    """Display user profile with navigation links."""
    
    # Generate security URLs
    change_password_url = url_for_security('change_password')
    logout_url = url_for_security('logout')
    
    # Add query parameters
    reset_url = get_url('security.forgot_password', 
                       qparams={'email': current_user.email})
    
    return render_template('profile.html',
                         change_password_url=change_password_url,
                         logout_url=logout_url,
                         reset_url=reset_url)

Token Generation and Validation

from flask_security import generate_token, verify_token

@app.route('/send-invite', methods=['POST'])
@roles_required('admin')
def send_invite():
    """Send invitation token to new user."""
    email = request.form.get('email')
    
    # Generate invitation token
    token_data = {'email': email, 'action': 'invite'}
    token = generate_token(token_data, salt='invite-salt')
    
    # Send invitation email
    invite_url = url_for('accept_invite', token=token, _external=True)
    send_mail(
        subject='You are invited to join our platform',
        recipient=email,
        template='invite_email',
        invite_url=invite_url
    )
    
    flash(f'Invitation sent to {email}')
    return redirect(url_for('admin_users'))

@app.route('/accept-invite/<token>')
def accept_invite(token):
    """Accept invitation using token."""
    
    # Verify token (valid for 7 days)
    token_data = verify_token(token, salt='invite-salt', max_age=604800)
    
    if not token_data:
        flash('Invalid or expired invitation link')
        return redirect(url_for('security.register'))
    
    # Pre-fill registration form with invited email
    return redirect(url_for('security.register', email=token_data['email']))

Password Validation

from flask_security import (
    password_length_validator, 
    password_complexity_validator,
    password_breached_validator
)

def validate_new_password(password):
    """Custom password validation with multiple checks."""
    
    try:
        # Check length requirements
        password_length_validator(password, min_length=8, max_length=128)
        
        # Check complexity requirements
        password_complexity_validator(password, {
            'uppercase': 1,
            'lowercase': 1, 
            'digits': 1,
            'symbols': 1
        })
        
        # Check against breach database
        password_breached_validator(password)
        
        return True
        
    except ValidationError as e:
        return False, str(e)

@app.route('/validate-password', methods=['POST'])
def validate_password_endpoint():
    """API endpoint for password validation."""
    password = request.json.get('password')
    
    is_valid, error_message = validate_new_password(password)
    
    return jsonify({
        'valid': is_valid,
        'error': error_message if not is_valid else None
    })

Email Communication

from flask_security import send_mail, MailUtil

# Initialize mail utility
mail_util = MailUtil(app)

@app.route('/send-welcome-email')
@login_required  
def send_welcome_email():
    """Send welcome email to new user."""
    
    success = send_mail(
        subject='Welcome to Our Platform!',
        recipient=current_user.email,
        template='welcome_email',
        user=current_user,
        login_url=url_for_security('login', _external=True)
    )
    
    if success:
        flash('Welcome email sent successfully')
    else:
        flash('Failed to send welcome email')
    
    return redirect(url_for('dashboard'))

@app.route('/send-custom-notification', methods=['POST'])
@roles_required('admin')
def send_custom_notification():
    """Send custom notification to users."""
    
    subject = request.form.get('subject')
    message = request.form.get('message')
    recipient_emails = request.form.getlist('recipients')
    
    sent_count = 0
    for email in recipient_emails:
        if mail_util.send_mail(
            template='notification_email',
            subject=subject,
            recipient=email,
            message=message,
            admin_name=current_user.email
        ):
            sent_count += 1
    
    flash(f'Notification sent to {sent_count} users')
    return redirect(url_for('admin_notifications'))

SMS Integration

from flask_security import SmsSenderFactory

# Configure SMS service
app.config['SECURITY_SMS_SERVICE'] = 'Twilio'
app.config['SECURITY_SMS_SERVICE_CONFIG'] = {
    'ACCOUNT_SID': 'your-account-sid',
    'AUTH_TOKEN': 'your-auth-token', 
    'FROM_NUMBER': '+1234567890'
}

# Create SMS sender
sms_sender = SmsSenderFactory.createSender(
    app.config['SECURITY_SMS_SERVICE'],
    **app.config['SECURITY_SMS_SERVICE_CONFIG']
)

@app.route('/send-sms-code', methods=['POST'])
@login_required
def send_sms_code():
    """Send SMS verification code to user."""
    
    if not current_user.us_phone_number:
        flash('Phone number not configured')
        return redirect(url_for('profile'))
    
    # Generate verification code
    code = generate_random_code(6)
    
    # Store code in session with expiration
    session['sms_verification_code'] = code
    session['sms_code_expires'] = (datetime.utcnow() + timedelta(minutes=5)).isoformat()
    
    # Send SMS
    message = f"Your verification code is: {code}"
    success = sms_sender.send_sms(
        from_number=app.config['SECURITY_SMS_SERVICE_CONFIG']['FROM_NUMBER'],
        to_number=current_user.us_phone_number,
        msg=message
    )
    
    if success:
        flash('Verification code sent to your phone')
    else:
        flash('Failed to send SMS')
    
    return redirect(url_for('verify_phone'))

def generate_random_code(length=6):
    """Generate random numeric code."""
    import random
    import string
    return ''.join(random.choices(string.digits, k=length))

TOTP Two-Factor Authentication

from flask_security import Totp

@app.route('/setup-2fa')
@login_required
def setup_2fa():
    """Setup TOTP two-factor authentication."""
    
    # Generate TOTP secret
    totp = Totp()
    
    # Store secret in session temporarily
    session['totp_setup_secret'] = totp.secret
    
    # Generate QR code for authenticator apps
    qr_code = totp.generate_qr_code(
        name=current_user.email,
        issuer='My Secure App'
    )
    
    return render_template('setup_2fa.html', 
                         secret=totp.secret,
                         qr_code=qr_code)

@app.route('/verify-2fa-setup', methods=['POST'])
@login_required
def verify_2fa_setup():
    """Verify TOTP setup with user-provided code."""
    
    code = request.form.get('code')
    secret = session.get('totp_setup_secret')
    
    if not secret:
        flash('Setup session expired')
        return redirect(url_for('setup_2fa'))
    
    # Verify the code
    totp = Totp(secret=secret)
    if totp.verify(code, window=1):
        # Save TOTP secret to user
        current_user.tf_totp_secret = secret
        current_user.tf_primary_method = 'authenticator'
        db.session.commit()
        
        # Clear setup session
        session.pop('totp_setup_secret', None)
        
        flash('Two-factor authentication enabled successfully')
        return redirect(url_for('profile'))
    else:
        flash('Invalid code. Please try again.')
        return redirect(url_for('setup_2fa'))

@app.route('/verify-2fa', methods=['GET', 'POST'])
@login_required
def verify_2fa():
    """Verify TOTP code for authentication."""
    
    if request.method == 'POST':
        code = request.form.get('code')
        
        if current_user.tf_totp_secret:
            totp = Totp(secret=current_user.tf_totp_secret)
            if totp.verify(code, window=1):
                session['2fa_verified'] = True
                return redirect(request.args.get('next', '/dashboard'))
            else:
                flash('Invalid authentication code')
    
    return render_template('verify_2fa.html')

Utility Class Integration

from flask_security import PasswordUtil, PhoneUtil, UsernameUtil

# Initialize utility classes
password_util = PasswordUtil(app)
phone_util = PhoneUtil(app)
username_util = UsernameUtil(app)

@app.route('/validate-profile', methods=['POST'])
@login_required
def validate_profile():
    """Validate user profile data."""
    
    username = request.form.get('username')
    phone = request.form.get('phone')
    new_password = request.form.get('new_password')
    
    errors = []
    
    # Validate username if provided
    if username:
        try:
            username_util.validate_username(username)
            normalized_username = username_util.normalize_username(username)
        except ValidationError as e:
            errors.append(f"Username: {e}")
    
    # Validate phone number if provided
    if phone:
        if phone_util.validate_phone_number(phone):
            normalized_phone = phone_util.normalize_phone_number(phone)
        else:
            errors.append("Invalid phone number format")
    
    # Validate new password if provided
    if new_password:
        try:
            password_util.validate_password(new_password)
        except ValidationError as e:
            errors.append(f"Password: {e}")
    
    if errors:
        return jsonify({'success': False, 'errors': errors})
    
    # Update user profile
    if username:
        current_user.username = normalized_username
    if phone:
        current_user.us_phone_number = normalized_phone
    if new_password:
        current_user.password = password_util.hash_password(new_password)
    
    db.session.commit()
    
    return jsonify({'success': True, 'message': 'Profile updated successfully'})

Custom Security Decorators Using Utilities

from functools import wraps
from flask_security import get_request_attr, naive_utcnow

def rate_limit(max_requests=10, window_seconds=60):
    """Rate limiting decorator using utilities."""
    
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            
            # Get client IP using utility
            client_ip = get_request_attr('remote_addr') or 'unknown'
            
            # Simple in-memory rate limiting (use Redis in production)
            current_time = naive_utcnow()
            
            if not hasattr(app, 'rate_limit_store'):
                app.rate_limit_store = {}
            
            key = f"rate_limit:{client_ip}:{f.__name__}"
            
            if key in app.rate_limit_store:
                requests, window_start = app.rate_limit_store[key]
                
                # Check if window expired
                if (current_time - window_start).total_seconds() > window_seconds:
                    # Reset window
                    app.rate_limit_store[key] = (1, current_time)
                elif requests >= max_requests:
                    # Rate limit exceeded
                    return jsonify({'error': 'Rate limit exceeded'}), 429
                else:
                    # Increment counter
                    app.rate_limit_store[key] = (requests + 1, window_start)
            else:
                # First request in window
                app.rate_limit_store[key] = (1, current_time)
            
            return f(*args, **kwargs)
        return decorated_function
    return decorator

@app.route('/api/sensitive-endpoint')
@login_required
@rate_limit(max_requests=5, window_seconds=60)
def sensitive_endpoint():
    """Rate-limited API endpoint."""
    return jsonify({'data': 'sensitive information'})

Configuration

Flask-Security utilities can be configured through various configuration variables:

# Email configuration
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = 'your-email@gmail.com'
app.config['MAIL_PASSWORD'] = 'your-password'

# Password validation configuration
app.config['SECURITY_PASSWORD_LENGTH_MIN'] = 8
app.config['SECURITY_PASSWORD_COMPLEXITY_CHECKER'] = 'zxcvbn'

# Token configuration
app.config['SECURITY_TOKEN_AUTHENTICATION_KEY'] = 'auth_token'
app.config['SECURITY_TOKEN_MAX_AGE'] = 86400  # 24 hours

# SMS configuration
app.config['SECURITY_SMS_SERVICE'] = 'Twilio'
app.config['SECURITY_SMS_SERVICE_CONFIG'] = {
    'ACCOUNT_SID': 'your-sid',
    'AUTH_TOKEN': 'your-token'
}

Security Considerations

Token Security

  • Use cryptographically secure random token generation
  • Implement proper token expiration and rotation
  • Store tokens securely with appropriate hashing
  • Validate token signatures to prevent tampering

Communication Security

  • Use TLS/SSL for all email and SMS communications
  • Validate recipient addresses before sending messages
  • Implement rate limiting for communication endpoints
  • Log security-related communications for audit trails

Password Security

  • Use strong password hashing algorithms (bcrypt, Argon2)
  • Implement comprehensive password policies
  • Check passwords against known breach databases
  • Provide clear feedback on password requirements

General Security

  • Validate all user inputs using utility functions
  • Implement proper error handling without information disclosure
  • Use secure random number generation for codes and tokens
  • Monitor and log security-related utility function usage

docs

authentication.md

authorization.md

core-setup.md

database.md

index.md

password-management.md

registration.md

two-factor.md

unified-signin.md

utilities.md

webauthn.md

tile.json