### Install Python Dependencies Source: https://github.com/bandwidth-samples/mfa-python-example-app/blob/master/README.md Install the required Python packages for the project using pip. This should be done after activating the virtual environment. ```bash pip install -r requirements.txt ``` -------------------------------- ### Run Flask Development Server Source: https://github.com/bandwidth-samples/mfa-python-example-app/blob/master/README.md Start the Flask development web server to run the application locally. Access the application via a web browser. ```bash python manage.py runserver ``` -------------------------------- ### Define User and Role Models Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Defines the database schema for users and roles using SQLAlchemy and Flask-User's UserMixin. Includes an example query to retrieve all users with the admin role. ```python from flask_user import UserMixin from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, validators from app import db class User(db.Model, UserMixin): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) # Authentication fields email = db.Column(db.Unicode(255), nullable=False, unique=True) email_confirmed_at = db.Column(db.DateTime()) password = db.Column(db.String(255), nullable=False, server_default='') active = db.Column('is_active', db.Boolean(), nullable=False, server_default='0') # User information first_name = db.Column(db.Unicode(50), nullable=False, server_default=u'') last_name = db.Column(db.Unicode(50), nullable=False, server_default=u'') # Role relationships roles = db.relationship('Role', secondary='users_roles', backref=db.backref('users', lazy='dynamic')) class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(50), nullable=False, unique=True) label = db.Column(db.Unicode(255), server_default=u'') # Example: Query users admin_users = User.query.join(User.roles).filter(Role.name == 'admin').all() ``` -------------------------------- ### Initialize Database Source: https://github.com/bandwidth-samples/mfa-python-example-app/blob/master/README.md Create database tables and populate initial roles and users. This command is essential for the application's data persistence. ```bash python manage.py init_db ``` -------------------------------- ### Initialize Database and Seed Data Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Commands for initializing the database and Python logic for creating default roles and users. ```bash # Initialize the database from command line python manage.py init_db # Output: Database has been initialized. # Start the development server python manage.py runserver # Server starts at http://localhost:5000 ``` ```python from flask import current_app from app import db from app.models.user_models import User, Role import datetime def find_or_create_user(first_name, last_name, email, password, role=None): """Find existing user or create new user""" user = User.query.filter(User.email == email).first() if not user: user = User( email=email, first_name=first_name, last_name=last_name, password=current_app.user_manager.password_manager.hash_password(password), active=True, email_confirmed_at=datetime.datetime.utcnow() ) if role: user.roles.append(role) db.session.add(user) return user def find_or_create_role(name, label): """Find existing role or create new role""" role = Role.query.filter(Role.name == name).first() if not role: role = Role(name=name, label=label) db.session.add(role) return role # Create admin role and users admin_role = find_or_create_role('admin', u'Admin') find_or_create_user(u'Admin', u'Example', u'admin@example.com', 'Password1', admin_role) find_or_create_user(u'Member', u'Example', u'member@example.com', 'Password1') db.session.commit() ``` -------------------------------- ### Clone and Set Up Python Virtual Environment Source: https://github.com/bandwidth-samples/mfa-python-example-app/blob/master/README.md Clone the code repository and set up a Python virtual environment for the project. This ensures dependencies are managed correctly. ```bash # Clone the code repository into ~/my_code/mfa-python-example-app mkdir -p ~/my_code cd ~/my_code git clone https://bandwidth.com/mfa-python-example-app.git mfa-python-example-app # Create the 'mfa-python-example-app' virtual environment cd mfa-python-example-app python3 -m venv .venv source .venv/bin/activate ``` -------------------------------- ### Initialize Flask Application Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Initializes the Flask application with necessary extensions. Use custom settings for testing environments. ```python from app import create_app, db # Create application with default settings app = create_app() # Create application with custom settings for testing app = create_app(extra_config_settings={ 'TESTING': True, 'LOGIN_DISABLED': False, 'MAIL_SUPPRESS_SEND': True, 'SERVER_NAME': 'localhost', 'SQLALCHEMY_DATABASE_URI': 'sqlite:///:memory:', 'WTF_CSRF_ENABLED': False, }) # Run the application if __name__ == "__main__": app.run(debug=True) ``` -------------------------------- ### Initialize Test Application and Fixtures Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Sets up a test Flask application with an in-memory SQLite database and disabled security features. Includes pytest fixtures for the application instance and test client. ```python import pytest from app import create_app, db as the_db from app.commands.init_db import init_db # Initialize test application the_app = create_app(dict( TESTING=True, LOGIN_DISABLED=False, MAIL_SUPPRESS_SEND=True, SERVER_NAME='localhost', SQLALCHEMY_DATABASE_URI='sqlite:///:memory:', WTF_CSRF_ENABLED=False, )) the_app.app_context().push() init_db() @pytest.fixture(scope='session') def app(): return the_app @pytest.fixture(scope='session') def client(app): return app.test_client() # Example test def test_page_urls(client): # Visit home page response = client.get('/', follow_redirects=True) assert response.status_code == 200 # Login as user response = client.post('/user/sign-in', follow_redirects=True, data=dict(email='member@example.com', password='Password1')) assert response.status_code == 200 ``` -------------------------------- ### Handle User Profile Updates Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Uses Flask-WTF to create a profile form and a route to process form submissions and update user records. ```python from flask import request, redirect, url_for, render_template from flask_user import current_user, login_required from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, validators from app import db class UserProfileForm(FlaskForm): first_name = StringField('First name', validators=[ validators.DataRequired('First name is required')]) last_name = StringField('Last name', validators=[ validators.DataRequired('Last name is required')]) submit = SubmitField('Save') @main_blueprint.route('/main/profile', methods=['GET', 'POST']) @login_required def user_profile_page(): form = UserProfileForm(request.form, obj=current_user) if request.method == 'POST' and form.validate(): form.populate_obj(current_user) db.session.commit() return redirect(url_for('main.home_page')) return render_template('main/user_profile_page.html', form=form) ``` -------------------------------- ### Run Automated Tests Source: https://github.com/bandwidth-samples/mfa-python-example-app/blob/master/README.md Execute the automated tests for the application using py.test. This helps ensure the application's functionality and stability. ```bash py.test tests/ ``` -------------------------------- ### Run Tests Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Commands to execute pytest tests from the command line, with options for running tests with code coverage. ```bash # Run tests from command line py.test tests/ # Run tests with coverage py.test tests/ --cov=app ``` -------------------------------- ### Protect Routes with Flask-User Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Demonstrates how to use decorators to restrict route access based on authentication status and user roles. ```python from flask import Blueprint, render_template from flask_user import login_required, roles_required main_blueprint = Blueprint('main', __name__, template_folder='templates') # Public route - accessible to anyone @main_blueprint.route('/') def home_page(): return render_template('main/home_page.html') # Protected route - requires authentication @main_blueprint.route('/member') @login_required def member_page(): return render_template('main/user_page.html') # Admin route - requires 'admin' role @main_blueprint.route('/admin') @roles_required('admin') def admin_page(): return render_template('main/admin_page.html') ``` -------------------------------- ### Render Form Fields with Macros Source: https://github.com/bandwidth-samples/mfa-python-example-app/blob/master/app/templates/common/form_macros.html Macros for rendering standard form fields, checkboxes, radio buttons, and submit buttons. These require WTForms field objects as input. ```jinja2 {% macro render_field(field, label=None, label_visible=true, right_url=None, right_label=None) -%} {% if field.type != 'HiddenField' and label_visible %} {% if not label %}{% set label=field.label.text %}{% endif %} {{ label|safe }} {% endif %} {{ field(class_='form-control', **kwargs) }} {% if field.errors %} {% for e in field.errors %} {{ e }} {% endfor %} {% endif %} {%- endmacro %} ``` ```jinja2 {% macro render_checkbox_field(field, label=None) -%} {% if not label %}{% set label=field.label.text %}{% endif %} {{ field(type='checkbox', **kwargs) }} {{ label }} {%- endmacro %} ``` ```jinja2 {% macro render_radio_field(field) -%} {% for value, label, checked in field.iter_choices() %} {{ label }} {% endfor %} {%- endmacro %} ``` ```jinja2 {% macro render_submit_field(field, label=None, tabindex=None) -%} {% if not label %}{% set label=field.label.text %}{% endif %} {#{{label}}#} {%- endmacro %} ``` -------------------------------- ### Request MFA Code via Bandwidth API Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Sends a two-factor authentication code to a user's phone via the Bandwidth MFA API. Ensure your credentials and account details are correctly configured. ```python import json import requests # Customer-specific configuration base64_encoded_username_and_password = '' headers = {'Authorization': 'Basic ' + base64_encoded_username_and_password} account_id = '' messaging_application_id = '' from_phone_num = '+15551234567' # E164 format # Send MFA code via Bandwidth API to_phone_num = '+15559876543' # User's phone in E164 format data = json.dumps({ "applicationId": messaging_application_id, "scope": "example", "to": to_phone_num, "from": from_phone_num }) response = requests.post( f'https://mfa.bandwidth.com/api/v1/accounts/{account_id}/code/messaging', headers=headers, data=data ) # Expected: 200 OK with code sent to user's phone print(f"Status: {response.status_code}") ``` -------------------------------- ### Verify MFA Code via Bandwidth API Source: https://context7.com/bandwidth-samples/mfa-python-example-app/llms.txt Validates the authentication code entered by the user against the Bandwidth MFA verification API. Redirects to member page on success or login page on failure. ```python import json import requests from flask import redirect, url_for, flash, request # Verify the code entered by user to_phone_num = '+15559876543' # User's phone in E164 format user_entered_code = request.form["two_factor_code"] data = json.dumps({ "applicationId": messaging_application_id, "scope": "example", "to": to_phone_num, "from": from_phone_num, "code": user_entered_code }) resp = requests.post( f'https://mfa.bandwidth.com/api/v1/accounts/{account_id}/code/verify', headers=headers, data=data ) resp_dict = resp.json() if (resp.status_code == 200) and isinstance(resp_dict, dict) and resp_dict.get('valid'): # Code is valid - grant access return redirect(url_for('main.member_page')) else: # Code is invalid - redirect to login flash('That code is invalid, please try again.') return redirect(url_for('user.login')) # Expected successful response: {"valid": true} # Expected failed response: {"valid": false} ``` -------------------------------- ### Delete SQLite DB for Schema Issues Source: https://github.com/bandwidth-samples/mfa-python-example-app/blob/master/README.md If encountering database schema issues after model changes, delete the 'app.sqlite' file to reset the database. This is a troubleshooting step. ```bash rm app.sqlite ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.