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

two-factor.mddocs/

Two-Factor Authentication

TOTP-based two-factor authentication, SMS support, recovery codes, backup authentication methods, and multi-factor security for enhanced account protection in Flask applications.

Capabilities

Two-Factor Authentication Forms

Forms for setting up and verifying two-factor authentication.

class TwoFactorSetupForm(Form):
    """
    Form for setting up two-factor authentication.
    
    Fields:
    - setup: Choice field for 2FA method selection
    - phone: Phone number field (for SMS)
    - submit: Submit button
    """
    setup: SelectField
    phone: StringField
    submit: SubmitField

class TwoFactorVerifyCodeForm(Form):
    """
    Form for verifying two-factor authentication codes.
    
    Fields:
    - code: Code verification field
    - submit: Submit button
    """
    code: StringField
    submit: SubmitField

class TwoFactorRescueForm(Form):
    """
    Form for two-factor authentication recovery.
    
    Fields:
    - help_setup: Choice field for recovery method
    - submit: Submit button
    """
    help_setup: SelectField
    submit: SubmitField

class TwoFactorSelectForm(Form):
    """
    Form for selecting two-factor authentication method.
    
    Fields:
    - which: Choice field for method selection
    - submit: Submit button
    """
    which: SelectField
    submit: SubmitField

Two-Factor Token Functions

Functions for sending and managing two-factor authentication tokens.

def tf_send_security_token(user, method, phone_number=None, **kwargs):
    """
    Send two-factor security token to user via specified method.
    
    Parameters:
    - user: User object to send token to
    - method: Delivery method ('sms', 'google-authenticator', 'mail')
    - phone_number: Phone number for SMS delivery (optional)
    - kwargs: Additional method-specific parameters
    
    Returns:
    True if token sent successfully, False otherwise
    """

TOTP (Time-based One-Time Password) Utility

Class for managing TOTP-based two-factor authentication using authenticator apps.

class Totp:
    """
    Time-based One-Time Password utility for authenticator app integration.
    """
    
    def __init__(self, secrets=None):
        """
        Initialize TOTP utility.
        
        Parameters:
        - secrets: Secret key for TOTP generation (optional)
        """
    
    def generate_password(self, timestamp=None):
        """
        Generate TOTP password for current time.
        
        Parameters:
        - timestamp: Custom timestamp (optional, defaults to current time)
        
        Returns:
        6-digit TOTP code as string
        """
    
    def verify(self, token, window=0, timestamp=None):
        """
        Verify TOTP token against expected value.
        
        Parameters:
        - token: TOTP token to verify
        - window: Time window for verification (default: 0)
        - timestamp: Custom timestamp (optional)
        
        Returns:
        True if token is valid, False otherwise
        """
    
    def get_totp_uri(self, username, issuer_name=None):
        """
        Generate TOTP URI for QR code generation.
        
        Parameters:
        - username: Username for TOTP account
        - issuer_name: Name of issuing service (optional)
        
        Returns:
        TOTP URI string for QR code
        """
    
    @property
    def secrets(self):
        """Get TOTP secret key."""
    
    @secrets.setter
    def secrets(self, value):
        """Set TOTP secret key."""

Recovery Codes Utility

Class for managing multi-factor recovery codes as backup authentication method.

class MfRecoveryCodesUtil:
    """
    Multi-factor recovery codes utility for backup authentication.
    """
    
    def __init__(self, app=None):
        """Initialize recovery codes utility."""
    
    def generate_codes(self, user, count=10):
        """
        Generate recovery codes for user.
        
        Parameters:
        - user: User object to generate codes for
        - count: Number of codes to generate (default: 10)
        
        Returns:
        List of recovery code strings
        """
    
    def verify_code(self, user, code):
        """
        Verify and consume recovery code.
        
        Parameters:
        - user: User object
        - code: Recovery code to verify
        
        Returns:
        True if code is valid and consumed, False otherwise
        """
    
    def get_remaining_codes(self, user):
        """
        Get count of remaining unused recovery codes.
        
        Parameters:
        - user: User object
        
        Returns:
        Number of remaining recovery codes
        """

Recovery Code Forms

Forms for managing recovery codes.

class MfRecoveryCodesForm(Form):
    """
    Form for generating and displaying recovery codes.
    
    Fields:
    - submit: Submit button for code generation
    """
    submit: SubmitField

class MfRecoveryForm(Form):
    """
    Form for recovery code authentication.
    
    Fields:
    - code: Recovery code field
    - submit: Submit button
    """
    code: StringField
    submit: SubmitField

Two-Factor Plugin System

Base classes for extending two-factor authentication with custom methods.

class TfPluginBase:
    """
    Base class for two-factor authentication plugins.
    """
    
    def get_setup_form(self):
        """Return setup form for this 2FA method."""
    
    def setup_tf(self, user, setup_data):
        """Setup two-factor authentication for user."""
    
    def send_token(self, user):
        """Send authentication token to user."""
    
    def verify_token(self, user, token):
        """Verify authentication token."""
    
    def is_setup(self, user):
        """Check if 2FA is set up for user."""
    
    def remove_tf(self, user):
        """Remove 2FA setup for user."""

class TfPlugin:
    """
    Two-factor authentication plugin manager.
    """
    
    def __init__(self, app=None):
        """Initialize plugin manager."""
    
    def register_plugin(self, name, plugin_class):
        """Register a 2FA plugin."""
    
    def get_plugin(self, name):
        """Get registered plugin by name."""

Usage Examples

Basic Two-Factor Setup

# Enable two-factor authentication
app.config['SECURITY_TWO_FACTOR'] = True
app.config['SECURITY_TWO_FACTOR_REQUIRED'] = False  # Optional by default
app.config['SECURITY_TWO_FACTOR_SMS_SERVICE'] = 'Dummy'  # For development

security = Security(app, user_datastore)

TOTP Authenticator App Setup

from flask_security import Totp

@app.route('/setup-authenticator')
@login_required
def setup_authenticator():
    if current_user.tf_totp_secret:
        flash('Two-factor authentication is already set up')
        return redirect('/profile')
    
    # Generate new TOTP secret
    totp = Totp()
    current_user.tf_totp_secret = totp.secrets
    
    # Generate QR code URI
    qr_uri = totp.get_totp_uri(
        username=current_user.email,
        issuer_name='My App'
    )
    
    db.session.commit()
    
    return render_template('setup_totp.html', 
                         secret=totp.secrets, 
                         qr_uri=qr_uri)

@app.route('/verify-totp', methods=['POST'])
@login_required  
def verify_totp():
    code = request.form.get('code')
    
    if current_user.tf_totp_secret:
        totp = Totp(current_user.tf_totp_secret)
        if totp.verify(code, window=1):
            current_user.tf_primary_method = 'authenticator'
            db.session.commit()
            flash('Two-factor authentication enabled successfully')
            return redirect('/profile')
    
    flash('Invalid verification code')
    return redirect('/setup-authenticator')

SMS Two-Factor Authentication

from flask_security import tf_send_security_token

@app.route('/setup-sms-2fa', methods=['POST'])
@login_required
def setup_sms_2fa():
    phone_number = request.form.get('phone')
    
    # Validate and save phone number
    current_user.tf_phone_number = phone_number
    current_user.tf_primary_method = 'sms'
    
    # Send verification code
    if tf_send_security_token(current_user, 'sms', phone_number=phone_number):
        flash('Verification code sent to your phone')
        return redirect('/verify-sms-2fa')
    else:
        flash('Failed to send verification code')
        return redirect('/setup-2fa')

@app.route('/verify-sms-2fa', methods=['POST'])
@login_required
def verify_sms_2fa():
    code = request.form.get('code')
    
    # Verify SMS code (implementation depends on SMS service)
    if verify_sms_code(current_user, code):
        db.session.commit()
        flash('SMS two-factor authentication enabled')
        return redirect('/profile')
    else:
        flash('Invalid verification code')
        return redirect('/verify-sms-2fa')

Recovery Codes Setup

from flask_security import MfRecoveryCodesUtil

@app.route('/generate-recovery-codes')
@login_required
def generate_recovery_codes():
    if not current_user.has_tf_setup():
        flash('Set up two-factor authentication first')
        return redirect('/setup-2fa')
    
    recovery_util = MfRecoveryCodesUtil()
    codes = recovery_util.generate_codes(current_user, count=10)
    
    return render_template('recovery_codes.html', codes=codes)

@app.route('/verify-recovery-code', methods=['POST'])
def verify_recovery_code():
    code = request.form.get('code')
    user = get_user_from_session()  # Get user being verified
    
    recovery_util = MfRecoveryCodesUtil()
    if recovery_util.verify_code(user, code):
        # Log user in and mark as verified
        login_user(user)
        flash('Logged in using recovery code')
        return redirect('/profile')
    else:
        flash('Invalid recovery code')
        return redirect('/2fa-verify')

Custom Two-Factor Plugin

from flask_security import TfPluginBase

class EmailTfPlugin(TfPluginBase):
    """Custom email-based 2FA plugin."""
    
    def setup_tf(self, user, setup_data):
        """Setup email 2FA for user."""
        user.tf_email_enabled = True
        return True
    
    def send_token(self, user):
        """Send 2FA code via email."""
        code = generate_random_code(6)
        user.tf_email_code = code
        user.tf_email_code_expires = datetime.utcnow() + timedelta(minutes=5)
        
        send_mail(
            subject='Your verification code',
            recipient=user.email,
            template='email_2fa_code.html',
            code=code
        )
        return True
    
    def verify_token(self, user, token):
        """Verify email 2FA code."""
        if (user.tf_email_code == token and 
            user.tf_email_code_expires > datetime.utcnow()):
            # Clear used code
            user.tf_email_code = None
            user.tf_email_code_expires = None
            return True
        return False
    
    def is_setup(self, user):
        """Check if email 2FA is set up."""
        return getattr(user, 'tf_email_enabled', False)

# Register custom plugin
tf_plugin = TfPlugin(app)
tf_plugin.register_plugin('email', EmailTfPlugin())

Enforcing Two-Factor Authentication

from flask_security import current_user
from functools import wraps

def tf_required(f):
    """Decorator to require two-factor authentication."""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for_security('login'))
        
        if not current_user.has_tf_setup():
            flash('Two-factor authentication is required')
            return redirect('/setup-2fa')
        
        if not session.get('tf_verified'):
            return redirect('/2fa-verify')
        
        return f(*args, **kwargs)
    return decorated_function

@app.route('/admin-panel')
@tf_required
def admin_panel():
    return render_template('admin.html')

Two-Factor Authentication in API

from flask_security import auth_required

@app.route('/api/sensitive-data')
@auth_required('token')
def sensitive_api_data():
    # Check if user has 2FA enabled and verified
    if current_user.has_tf_setup() and not session.get('tf_verified'):
        return jsonify({
            'error': 'Two-factor authentication required',
            'tf_required': True,
            'tf_methods': current_user.get_tf_methods()
        }), 403
    
    return jsonify({'data': 'sensitive information'})

@app.route('/api/verify-2fa', methods=['POST'])
@auth_required('token')
def api_verify_2fa():
    code = request.json.get('code')
    method = request.json.get('method', 'authenticator')
    
    if method == 'authenticator' and current_user.tf_totp_secret:
        totp = Totp(current_user.tf_totp_secret)
        if totp.verify(code, window=1):
            session['tf_verified'] = True
            return jsonify({'success': True})
    
    return jsonify({'error': 'Invalid verification code'}), 400

Configuration Options

Key configuration variables for two-factor authentication:

# Two-factor authentication
app.config['SECURITY_TWO_FACTOR'] = True
app.config['SECURITY_TWO_FACTOR_REQUIRED'] = False
app.config['SECURITY_TWO_FACTOR_SMS_SERVICE'] = 'Dummy'  # or 'Twilio', etc.

# TOTP settings
app.config['SECURITY_TOTP_SECRETS'] = {'1': 'secret-key-here'}
app.config['SECURITY_TOTP_ISSUER'] = 'My Application'

# SMS settings
app.config['SECURITY_SMS_SERVICE'] = 'Dummy'
app.config['SECURITY_SMS_SERVICE_CONFIG'] = {}

# Recovery codes
app.config['SECURITY_RECOVERY_CODES'] = True
app.config['SECURITY_RECOVERY_CODES_N'] = 10

# Two-factor URLs
app.config['SECURITY_TWO_FACTOR_SETUP_URL'] = '/tf-setup'
app.config['SECURITY_TWO_FACTOR_TOKEN_VALIDATION_URL'] = '/tf-validate'
app.config['SECURITY_TWO_FACTOR_RESCUE_URL'] = '/tf-rescue'

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