Quickly add security features to your Flask application.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
User registration forms, email confirmation workflow, account activation functionality, and user account management for onboarding new users to Flask applications.
Forms for user registration with various configurations and validation options.
class RegisterForm(Form):
"""
Basic user registration form.
Fields:
- email: Email address field with validation
- password: Password field with confirmation
- password_confirm: Password confirmation field
- submit: Submit button
"""
email: StringField
password: PasswordField
password_confirm: PasswordField
submit: SubmitField
class RegisterFormV2(Form):
"""
Enhanced registration form with additional features.
Fields:
- email: Email address field
- username: Username field (if username is enabled)
- password: Password field
- password_confirm: Password confirmation field
- submit: Submit button
"""
email: StringField
username: StringField
password: PasswordField
password_confirm: PasswordField
submit: SubmitField
class ConfirmRegisterForm(Form):
"""
Registration form requiring email confirmation.
Fields:
- email: Email address field
- password: Password field
- password_confirm: Password confirmation field
- submit: Submit button
"""
email: StringField
password: PasswordField
password_confirm: PasswordField
submit: SubmitFieldCore functions for registering new users and managing the registration process.
def register_user(**kwargs):
"""
Register a new user with provided attributes.
Parameters:
- email: User's email address
- password: User's password (will be hashed)
- username: Username (optional, if enabled)
- active: Whether user should be active immediately (default: True)
- confirmed_at: Confirmation timestamp (optional)
- roles: List of roles to assign to user (optional)
- **kwargs: Additional user attributes
Returns:
Created user object
Raises:
UserAlreadyExistsError: If user with email already exists
"""
def register_existing(user, **kwargs):
"""
Handle registration attempt for existing user (e.g., OAuth scenarios).
Parameters:
- user: Existing user object
- **kwargs: Additional attributes to update
Returns:
Updated user object
"""Functions for managing email confirmation workflow and account activation.
def send_confirmation_instructions(user):
"""
Send email confirmation instructions to user.
Parameters:
- user: User object to send confirmation to
Returns:
True if email sent successfully, False otherwise
"""
def generate_confirmation_token(user):
"""
Generate email confirmation token for user.
Parameters:
- user: User object to generate token for
Returns:
Confirmation token string
"""
def generate_confirmation_link(user):
"""
Generate email confirmation URL for user.
Parameters:
- user: User object to generate link for
Returns:
Full confirmation URL string
"""
def confirm_user(user):
"""
Confirm user's email address and activate account.
Parameters:
- user: User object to confirm
Returns:
True if user confirmed successfully, False otherwise
"""
def confirm_email_token_status(token):
"""
Validate email confirmation token and return status.
Parameters:
- token: Confirmation token to validate
Returns:
Tuple of (expired: bool, invalid: bool, user: User|None)
"""
def requires_confirmation(user):
"""
Check if user requires email confirmation.
Parameters:
- user: User object to check
Returns:
True if user needs confirmation, False otherwise
"""Forms for handling email confirmation workflow.
class SendConfirmationForm(Form):
"""
Form for sending/resending email confirmation.
Fields:
- user: Email or username field
- submit: Submit button
"""
user: StringField
submit: SubmitFieldReusable mixins for building custom registration forms.
class RegisterFormMixin:
"""
Base mixin for registration forms providing common functionality.
"""
class UserEmailFormMixin:
"""
Mixin providing email field with validation.
"""
class UniqueEmailFormMixin:
"""
Mixin providing email uniqueness validation.
"""
class PasswordFormMixin:
"""
Mixin providing password field with validation.
"""
class NewPasswordFormMixin:
"""
Mixin providing new password field with confirmation.
"""
class PasswordConfirmFormMixin:
"""
Mixin providing password confirmation field and validation.
"""Dynamic form building functions for customizing registration forms.
def build_register_form(base_class=RegisterForm):
"""
Build registration form class with current configuration.
Parameters:
- base_class: Base form class to extend (default: RegisterForm)
Returns:
Dynamically created form class
"""
def unique_identity_attribute(form, field):
"""
Validator for ensuring unique identity attributes (email, username).
Parameters:
- form: Form instance
- field: Field being validated
Raises:
ValidationError: If identity attribute is not unique
"""from flask_security import Security, RegisterForm
# Enable registration in configuration
app.config['SECURITY_REGISTERABLE'] = True
# Use default registration form
security = Security(app, user_datastore)
# Access registration URL: /registerfrom flask_security import RegisterForm
from wtforms import StringField, TextAreaField
from wtforms.validators import DataRequired, Length
class ExtendedRegisterForm(RegisterForm):
first_name = StringField('First Name', validators=[DataRequired()])
last_name = StringField('Last Name', validators=[DataRequired()])
bio = TextAreaField('Bio', validators=[Length(max=500)])
# Use custom form
security = Security(app, user_datastore, register_form=ExtendedRegisterForm)# Enable confirmable feature
app.config['SECURITY_CONFIRMABLE'] = True
app.config['SECURITY_CONFIRM_EMAIL_WITHIN'] = '5 days'
# Use confirmation registration form
security = Security(app, user_datastore, confirm_register_form=ConfirmRegisterForm)from flask_security import register_user, hash_password
@app.route('/admin/create-user', methods=['POST'])
@roles_required('admin')
def create_user():
email = request.form['email']
password = request.form['password']
try:
user = register_user(
email=email,
password=password,
active=True,
confirmed_at=datetime.utcnow(),
roles=['user']
)
db.session.commit()
flash(f'User {email} created successfully')
return redirect('/admin/users')
except Exception as e:
flash(f'Error creating user: {str(e)}')
return redirect('/admin/create-user')from flask_security import send_confirmation_instructions, confirm_user
@app.route('/resend-confirmation')
@login_required
def resend_confirmation():
if requires_confirmation(current_user):
send_confirmation_instructions(current_user)
flash('Confirmation instructions sent to your email')
else:
flash('Your email is already confirmed')
return redirect('/profile')
@app.route('/admin/confirm-user/<int:user_id>')
@roles_required('admin')
def admin_confirm_user(user_id):
user = User.query.get_or_404(user_id)
if confirm_user(user):
db.session.commit()
flash(f'User {user.email} confirmed successfully')
else:
flash('User was already confirmed')
return redirect('/admin/users')from flask_security import register_user, find_role
@app.route('/register-teacher', methods=['POST'])
def register_teacher():
# Custom registration endpoint for teachers
form = TeacherRegistrationForm()
if form.validate_on_submit():
teacher_role = find_role('teacher')
user = register_user(
email=form.email.data,
password=form.password.data,
first_name=form.first_name.data,
last_name=form.last_name.data,
school=form.school.data,
roles=[teacher_role],
active=False, # Require admin approval
)
db.session.commit()
# Send notification to admins
send_teacher_registration_notification(user)
flash('Registration submitted for approval')
return redirect('/login')
return render_template('register_teacher.html', form=form)from flask_security.signals import user_registered
@user_registered.connect_via(app)
def user_registered_sighandler(sender, **extra):
user = extra['user']
# Send welcome email
send_welcome_email(user)
# Log registration
app.logger.info(f'New user registered: {user.email}')
# Add to mailing list (example)
subscribe_to_newsletter(user.email)from flask_security import confirm_email_token_status
@app.route('/confirm/<token>')
def confirm_email(token):
expired, invalid, user = confirm_email_token_status(token)
if expired:
flash('The confirmation link has expired')
return redirect('/resend-confirmation')
if invalid or not user:
flash('Invalid confirmation link')
return redirect('/login')
if user.confirmed_at:
flash('Email already confirmed')
else:
confirm_user(user)
db.session.commit()
flash('Email confirmed successfully! You can now log in.')
return redirect('/login')from wtforms.validators import ValidationError
from flask_security import unique_identity_attribute
class CustomRegisterForm(RegisterForm):
company = StringField('Company', validators=[DataRequired()])
def validate_email(self, field):
# Custom email domain validation
allowed_domains = ['company.com', 'partner.com']
domain = field.data.split('@')[1].lower()
if domain not in allowed_domains:
raise ValidationError('Email must be from an approved domain')
def validate_company(self, field):
# Custom company validation
valid_companies = ['ACME Corp', 'Global Inc', 'Tech Solutions']
if field.data not in valid_companies:
raise ValidationError('Invalid company selection')Key configuration variables for registration and confirmation:
# Registration settings
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_REGISTER_URL'] = '/register'
app.config['SECURITY_POST_REGISTER_REDIRECT_ENDPOINT'] = '/profile'
# Email confirmation settings
app.config['SECURITY_CONFIRMABLE'] = True
app.config['SECURITY_CONFIRM_EMAIL_WITHIN'] = '5 days'
app.config['SECURITY_CONFIRM_URL'] = '/confirm'
app.config['SECURITY_POST_CONFIRM_REDIRECT_ENDPOINT'] = '/profile'
# Auto-login after registration/confirmation
app.config['SECURITY_AUTO_LOGIN_AFTER_CONFIRM'] = True
app.config['SECURITY_AUTO_LOGIN_AFTER_REGISTER'] = False