CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/pypi-flask-security

Simple security for Flask apps

Overview
Eval results
Files

security-features.mddocs/

Security Features

Flask-Security provides optional security features that can be enabled through configuration. These features include email confirmation, password recovery, user registration, password changing, and passwordless authentication. Each feature can be independently enabled and customized.

Capabilities

Email Confirmation (Confirmable)

Functions for managing email confirmation workflows when SECURITY_CONFIRMABLE is enabled.

def send_confirmation_instructions(user):
    """
    Send confirmation instructions to user via email.
    
    Args:
        user: User instance requiring confirmation
        
    Returns:
        None
    """

def generate_confirmation_link(user):
    """
    Generate confirmation URL and token for user.
    
    Args:
        user: User instance
        
    Returns:
        str: Confirmation URL
    """

def generate_confirmation_token(user):
    """
    Generate confirmation token for user.
    
    Args:
        user: User instance
        
    Returns:
        str: Confirmation token
    """

def requires_confirmation(user):
    """
    Check if user requires email confirmation.
    
    Args:
        user: User instance
        
    Returns:
        bool: True if user needs confirmation
    """

def confirm_email_token_status(token):
    """
    Validate confirmation token status.
    
    Args:
        token (str): Confirmation token
        
    Returns:
        tuple: (expired, invalid, user) status
    """

def confirm_user(user):
    """
    Mark user as confirmed and update timestamp.
    
    Args:
        user: User instance to confirm
        
    Returns:
        bool: True if confirmation successful
    """

Password Recovery (Recoverable)

Functions for password reset workflows when SECURITY_RECOVERABLE is enabled.

def send_reset_password_instructions(user):
    """
    Send password reset instructions to user via email.
    
    Args:
        user: User instance requesting password reset
        
    Returns:
        None
    """

def send_password_reset_notice(user):
    """
    Send password reset notification to user.
    
    Args:
        user: User whose password was reset
        
    Returns:
        None
    """

def generate_reset_password_token(user):
    """
    Generate password reset token for user.
    
    Args:
        user: User instance
        
    Returns:
        str: Password reset token
    """

def reset_password_token_status(token):
    """
    Validate password reset token status.
    
    Args:
        token (str): Reset token
        
    Returns:
        tuple: (expired, invalid, user) status
    """

def update_password(user, password):
    """
    Update user password and handle related operations.
    
    Args:
        user: User instance
        password (str): New plain text password
        
    Returns:
        None
    """

User Registration (Registerable)

Functions for user registration when SECURITY_REGISTERABLE is enabled.

def register_user(**kwargs):
    """
    Register a new user with the provided data.
    
    Args:
        **kwargs: User data (email, password, etc.)
        
    Returns:
        User: Newly created user instance
    """

Password Changes (Changeable)

Functions for password change workflows when SECURITY_CHANGEABLE is enabled.

def send_password_changed_notice(user):
    """
    Send password change notification to user.
    
    Args:
        user: User whose password was changed
        
    Returns:
        None
    """

def change_user_password(user, password):
    """
    Change user password and handle notifications.
    
    Args:
        user: User instance
        password (str): New plain text password
        
    Returns:
        None
    """

Passwordless Login (Passwordless)

Functions for passwordless authentication when SECURITY_PASSWORDLESS is enabled.

def send_login_instructions(user):
    """
    Send login instructions with token to user via email.
    
    Args:
        user: User instance requesting passwordless login
        
    Returns:
        None
    """

def generate_login_token(user):
    """
    Generate login token for passwordless authentication.
    
    Args:
        user: User instance
        
    Returns:
        str: Login token
    """

def login_token_status(token):
    """
    Validate login token status.
    
    Args:
        token (str): Login token
        
    Returns:
        tuple: (expired, invalid, user) status
    """

Configuration and Feature Enabling

Feature Toggle Configuration

# Enable/disable features in Flask configuration
app.config['SECURITY_CONFIRMABLE'] = True        # Email confirmation
app.config['SECURITY_REGISTERABLE'] = True       # User registration
app.config['SECURITY_RECOVERABLE'] = True        # Password recovery
app.config['SECURITY_CHANGEABLE'] = True         # Password changing
app.config['SECURITY_PASSWORDLESS'] = True       # Passwordless login
app.config['SECURITY_TRACKABLE'] = True          # User activity tracking

Email Configuration

# Email settings for feature notifications
app.config['SECURITY_EMAIL_SENDER'] = 'noreply@example.com'
app.config['SECURITY_SEND_REGISTER_EMAIL'] = True
app.config['SECURITY_SEND_PASSWORD_CHANGE_EMAIL'] = True
app.config['SECURITY_SEND_PASSWORD_RESET_EMAIL'] = True
app.config['SECURITY_SEND_PASSWORD_RESET_NOTICE_EMAIL'] = True

# Time limits for tokens
app.config['SECURITY_CONFIRM_EMAIL_WITHIN'] = '5 days'
app.config['SECURITY_RESET_PASSWORD_WITHIN'] = '5 days'
app.config['SECURITY_LOGIN_WITHIN'] = '1 days'

Usage Examples

Email Confirmation Workflow

from flask_security import register_user, send_confirmation_instructions

# Enable confirmable feature
app.config['SECURITY_CONFIRMABLE'] = True
app.config['SECURITY_LOGIN_WITHOUT_CONFIRMATION'] = False

@app.route('/register', methods=['POST'])
def register():
    email = request.form.get('email')
    password = request.form.get('password')
    
    # Register user (automatically unconfirmed)
    user = register_user(email=email, password=password)
    
    # Send confirmation email
    send_confirmation_instructions(user)
    
    return "Please check your email to confirm your account"

@app.route('/confirm/<token>')
def confirm_email(token):
    expired, invalid, user = confirm_email_token_status(token)
    
    if expired:
        return "Confirmation link has expired"
    if invalid:
        return "Invalid confirmation link"
    
    # Confirm the user
    if confirm_user(user):
        login_user(user)
        return "Email confirmed! You are now logged in."
    
    return "Confirmation failed"

# Check if user needs confirmation
@app.before_request
def check_confirmation():
    if (current_user.is_authenticated and 
        requires_confirmation(current_user)):
        return redirect(url_for('send_confirmation'))

Password Recovery Workflow

from flask_security import send_reset_password_instructions, update_password

# Enable recoverable feature
app.config['SECURITY_RECOVERABLE'] = True

@app.route('/forgot-password', methods=['POST'])
def forgot_password():
    email = request.form.get('email')
    user = user_datastore.find_user(email=email)
    
    if user:
        send_reset_password_instructions(user)
    
    # Always show success to prevent email enumeration
    return "Password reset instructions sent"

@app.route('/reset-password/<token>', methods=['GET', 'POST'])
def reset_password(token):
    expired, invalid, user = reset_password_token_status(token)
    
    if expired or invalid:
        return "Invalid or expired reset link"
    
    if request.method == 'POST':
        new_password = request.form.get('password')
        update_password(user, new_password)
        
        # Send notification
        send_password_reset_notice(user)
        
        return "Password updated successfully"
    
    return render_template('reset_password.html', token=token)

User Registration

from flask_security import register_user

# Enable registration
app.config['SECURITY_REGISTERABLE'] = True

@app.route('/api/register', methods=['POST'])
def api_register():
    data = request.get_json()
    
    try:
        user = register_user(
            email=data['email'],
            password=data['password'],
            first_name=data.get('first_name'),
            last_name=data.get('last_name')
        )
        
        if app.config.get('SECURITY_CONFIRMABLE'):
            return {
                'message': 'Registration successful. Please confirm your email.',
                'requires_confirmation': True
            }
        else:
            login_user(user)
            return {
                'message': 'Registration successful',
                'user': user.get_security_payload(),
                'auth_token': user.get_auth_token()
            }
    
    except Exception as e:
        return {'error': str(e)}, 400

Password Change

from flask_security import change_user_password, verify_password

# Enable changeable feature
app.config['SECURITY_CHANGEABLE'] = True

@app.route('/change-password', methods=['POST'])
@login_required
def change_password():
    current_password = request.form.get('current_password')
    new_password = request.form.get('new_password')
    
    # Verify current password
    if not verify_password(current_password, current_user.password):
        return "Current password is incorrect", 400
    
    # Change password
    change_user_password(current_user, new_password)
    
    return "Password changed successfully"

# Force password change for new users
@app.before_request
def check_password_change():
    if (current_user.is_authenticated and 
        getattr(current_user, 'force_password_change', False)):
        if request.endpoint != 'change_password':
            return redirect(url_for('change_password'))

Passwordless Login

from flask_security import send_login_instructions, login_token_status

# Enable passwordless feature
app.config['SECURITY_PASSWORDLESS'] = True

@app.route('/passwordless-login', methods=['POST'])
def passwordless_login():
    email = request.form.get('email')
    user = user_datastore.find_user(email=email)
    
    if user and user.is_active:
        send_login_instructions(user)
    
    return "Login instructions sent to your email"

@app.route('/login/<token>')
def token_login(token):
    expired, invalid, user = login_token_status(token)
    
    if expired:
        return "Login link has expired"
    if invalid:
        return "Invalid login link"
    
    # Log in the user
    login_user(user)
    return redirect(url_for('dashboard'))

User Activity Tracking

# Enable tracking feature
app.config['SECURITY_TRACKABLE'] = True

@app.route('/user-stats')
@login_required
def user_stats():
    return {
        'last_login_at': current_user.last_login_at,
        'current_login_at': current_user.current_login_at,
        'last_login_ip': current_user.last_login_ip,
        'current_login_ip': current_user.current_login_ip,
        'login_count': current_user.login_count
    }

# Add tracking fields to User model
class User(db.Model, UserMixin):
    # ... other fields ...
    
    # Tracking fields (automatically managed by Flask-Security)
    last_login_at = db.Column(db.DateTime())
    current_login_at = db.Column(db.DateTime())
    last_login_ip = db.Column(db.String(100))
    current_login_ip = db.Column(db.String(100))
    login_count = db.Column(db.Integer)

Custom Feature Integration

from flask_security.signals import user_registered, user_confirmed

# Custom welcome workflow
@user_registered.connect_via(app)
def send_welcome_series(sender, **extra):
    user = extra['user']
    
    if app.config.get('SECURITY_CONFIRMABLE'):
        # Schedule welcome series after confirmation
        schedule_task('send_welcome_series', user.id, delay='1 hour')
    else:
        # Send immediately
        send_welcome_email(user)

@user_confirmed.connect_via(app)
def handle_confirmation(sender, **extra):
    user = extra['user']
    
    # Grant default role
    default_role = user_datastore.find_role('member')
    user_datastore.add_role_to_user(user, default_role)
    
    # Send welcome email
    send_welcome_email(user)
    
    # Start onboarding process
    start_onboarding_flow(user)
    
    user_datastore.commit()
tessl i tessl/pypi-flask-security@3.0.0

docs

authentication.md

authorization.md

core-extension.md

data-storage.md

forms.md

index.md

security-features.md

signals.md

user-role-models.md

tile.json