### Basic Flask-SQLAlchemy Application Setup Source: https://flask-security.readthedocs.io/en/stable/quickstart Demonstrates a minimal Flask application using Flask-SQLAlchemy and Flask-Security. It sets up a database, defines user and role models, configures security settings, and creates an initial user. This example uses an in-memory SQLite database. ```python import os from flask import Flask, render_template_string from flask_sqlalchemy import SQLAlchemy from flask_security import Security, SQLAlchemyUserDatastore, auth_required, hash_password from flask_security.models import fsqla_v3 as fsqla # Create app app = Flask(__name__) app.config['DEBUG'] = True # Generate a nice key using secrets.token_urlsafe() app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw') # Generate a good salt for password hashing using: secrets.SystemRandom().getrandbits(128) app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634') # have session and remember cookie be samesite (flask/flask_login) app.config["REMEMBER_COOKIE_SAMESITE"] = "strict" app.config["SESSION_COOKIE_SAMESITE"] = "strict" # Use an in-memory db app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://' # As of Flask-SQLAlchemy 2.4.0 it is easy to pass in options directly to the # underlying engine. This option makes sure that DB connections from the # pool are still valid. Important for entire application since # many DBaaS options automatically close idle connections. app.config["SQLALCHEMY_ENGINE_OPTIONS"] = { "pool_pre_ping": True, } app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # Create database connection object db = SQLAlchemy(app) # Define models fsqla.FsModels.set_db_info(db) class Role(db.Model, fsqla.FsRoleMixin): pass class User(db.Model, fsqla.FsUserMixin): pass # Setup Flask-Security user_datastore = SQLAlchemyUserDatastore(db, User, Role) security = Security(app, user_datastore) # Views @app.route("/") @auth_required() def home(): return render_template_string("Hello {{ current_user.email }}") # one time setup with app.app_context(): # Create User to test with db.create_all() if not security.datastore.find_user(email="test@me.com"): security.datastore.create_user(email="test@me.com", password=hash_password("password")) db.session.commit() if __name__ == '__main__': app.run() ``` -------------------------------- ### Basic SQLAlchemy Application Setup Source: https://flask-security.readthedocs.io/en/stable/quickstart This example demonstrates setting up a Flask application using SQLAlchemy directly, without Flask-SQLAlchemy. It separates concerns into `app.py`, `database.py`, and `models.py`. The application integrates Flask-Security for authentication and permission checks. Key components include database session management and declarative model definitions. ```python import os from flask import Flask, render_template_string from flask_security import Security, current_user, auth_required, hash_password, \ SQLAlchemySessionUserDatastore, permissions_accepted from database import db_session, init_db from models import User, Role # Create app app = Flask(__name__) app.config['DEBUG'] = True # Generate a nice key using secrets.token_urlsafe() app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw') # Generate a good salt for password hashing using: secrets.SystemRandom().getrandbits(128) app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634') # Don't worry if email has findable domain app.config["SECURITY_EMAIL_VALIDATOR_ARGS"] = {"check_deliverability": False} # manage sessions per request - make sure connections are closed and returned app.teardown_appcontext(lambda exc: db_session.close()) # Setup Flask-Security user_datastore = SQLAlchemySessionUserDatastore(db_session, User, Role) security = Security(app, user_datastore) # Views @app.route("/") @auth_required() def home(): return render_template_string('Hello {{current_user.email}}!') @app.route("/user") @auth_required() @permissions_accepted("user-read") def user_home(): return render_template_string("Hello {{ current_user.email }} you are a user!") ``` -------------------------------- ### Peewee Application Setup with Flask-Security Source: https://flask-security.readthedocs.io/en/stable/quickstart Illustrates a quick start for a Flask application using Flask-Security with Peewee as the ORM. It includes user and role models, database setup, and a basic authenticated route. Requires Flask, Peewee, and Flask-Security. ```python import os from flask import Flask, render_template_string from playhouse.flask_utils import FlaskDB from peewee import * from flask_security import Security, PeeweeUserDatastore, \ UserMixin, RoleMixin, auth_required, hash_password # Create app app = Flask(__name__) app.config['DEBUG'] = True # Generate a nice key using secrets.token_urlsafe() app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw') # Generate a good salt for password hashing using: secrets.SystemRandom().getrandbits(128) app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634') app.config['DATABASE'] = { 'name': 'example.db', 'engine': 'peewee.SqliteDatabase', } # Create database connection object db = FlaskDB(app) class Role(RoleMixin, db.Model): name = CharField(unique=True) description = TextField(null=True) permissions = TextField(null=True) # N.B. order is important since db.Model also contains a get_id() - # we need the one from UserMixin. class User(UserMixin, db.Model): email = TextField() password = TextField() active = BooleanField(default=True) fs_uniquifier = TextField(null=False) confirmed_at = DateTimeField(null=True) class UserRoles(db.Model): # Because peewee does not come with built-in many-to-many # relationships, we need this intermediary class to link # user to roles. user = ForeignKeyField(User, related_name='roles') role = ForeignKeyField(Role, related_name='users') name = property(lambda self: self.role.name) description = property(lambda self: self.role.description) def get_permissions(self): return self.role.get_permissions() # Setup Flask-Security user_datastore = PeeweeUserDatastore(db, User, Role, UserRoles) security = Security(app, user_datastore) # Views @app.route('/') @auth_required() def home(): return render_template_string("Hello {{ current_user.email }}") # one time setup with app.app_context(): # Create a user to test with for Model in (Role, User, UserRoles): Model.drop_table(fail_silently=True) Model.create_table(fail_silently=True) if not security.datastore.find_user(email="test@me.com"): security.datastore.create_user(email="test@me.com", password=hash_password("password")) if __name__ == '__main__': app.run() ``` -------------------------------- ### Flask-SQLAlchemy-Lite App Setup with Models Source: https://flask-security.readthedocs.io/en/stable/quickstart This snippet illustrates a quick start with Flask-SQLAlchemy-Lite, utilizing built-in model mixins for roles and users. It sets up Flask, configures database connection (in-memory SQLite), defines models, and integrates Flask-Security with user datastore creation and initial user setup. Dependencies include Flask, Flask-SQLAlchemy-Lite, and Flask-Security. ```python import os from sqlalchemy.orm import DeclarativeBase from flask import Flask, render_template_string from flask_sqlalchemy_lite import SQLAlchemy from flask_security import Security, FSQLALiteUserDatastore, auth_required, hash_password from flask_security.models import sqla as sqla # Create app app = Flask(__name__) app.config['DEBUG'] = True # Generate a nice key using secrets.token_urlsafe() app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw') # Generate a good salt for password hashing using: secrets.SystemRandom().getrandbits(128) app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634') # have session and remember cookie be samesite (flask/flask_login) app.config["REMEMBER_COOKIE_SAMESITE"] = "strict" app.config["SESSION_COOKIE_SAMESITE"] = "strict" # Use an in-memory db app.config |= { "SQLALCHEMY_ENGINES": { "default": {"url": "sqlite:///:memory:", "pool_pre_ping": True}, }, } # Create database connection object db = SQLAlchemy(app) # Define models class Model(DeclarativeBase): pass # NOTE: call this PRIOR to declaring models sqla.FsModels.set_db_info(base_model=Model) class Role(Model, sqla.FsRoleMixin): __tablename__ = "role" pass class User(Model, sqla.FsUserMixin): __tablename__ = "user" pass # Setup Flask-Security user_datastore = FSQLALiteUserDatastore(db, User, Role) security = Security(app, user_datastore) # Views @app.route("/") @auth_required() def home(): return render_template_string("Hello {{ current_user.email }}") # one time setup with app.app_context(): # Create User to test with Model.metadata.create_all(db.engine) if not security.datastore.find_user(email="test@me.com"): security.datastore.create_user(email="test@me.com", password=hash_password("password")) db.session.commit() if __name__ == '__main__': app.run() ``` -------------------------------- ### Basic Flask Application Setup with SQLAlchemy Source: https://flask-security.readthedocs.io/en/stable/quickstart A basic Flask application setup using SQLAlchemy for database integration with Flask-Security. It includes initializing the database, creating a user and role, and running the Flask development server. ```python from flask import Flask from database import init_db, db_session from flask_security import Security, SQLAlchemyUserDatastore, hash_password import models app = Flask(__name__) # Setup SQLAlchemy app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Setup Flask-Security security = Security(app, SQLAlchemyUserDatastore(db_session, models.User, models.Role)) # one time setup with app.app_context(): init_db() # Create a user and role to test with security.datastore.find_or_create_role( name="user", permissions={"user-read", "user-write"} ) db_session.commit() if not security.datastore.find_user(email="test@me.com"): security.datastore.create_user(email="test@me.com", password=hash_password("password"), roles=["user"]) db_session.commit() if __name__ == '__main__': # run application (can also use flask run) app.run() ``` -------------------------------- ### MongoEngine Installation Requirements Source: https://flask-security.readthedocs.io/en/stable/quickstart Details the installation steps for using Flask-Security with MongoEngine. It involves creating a virtual environment, activating it, and then installing the necessary packages using pip. ```bash $ python3 -m venv pymyenv $ . pymyenv/bin/activate $ pip install flask-security[common] mongoengine ``` -------------------------------- ### Install Flask-Security with SQLAlchemy-Lite Source: https://flask-security.readthedocs.io/en/stable/quickstart Installs Flask-Security with common components, SQLAlchemy, and Flask-SQLAlchemy-Lite. This installation requires Python version 3.10 or newer. ```bash python3 -m venv pymyenv . pymyenv/bin/activate pip install flask-security[common] sqlalchemy flask-sqlalchemy-lite ``` -------------------------------- ### Install Flask-Security with SQLAlchemy Source: https://flask-security.readthedocs.io/en/stable/quickstart Installs Flask-Security with the necessary SQLAlchemy and common components for application integration. It also sets up a Python virtual environment. ```bash python3 -m venv pymyenv . pymyenv/bin/activate pip install flask-security[fsqla,common] ``` -------------------------------- ### Peewee Installation Requirements Source: https://flask-security.readthedocs.io/en/stable/quickstart Details the installation steps for using Flask-Security with Peewee. It involves creating a virtual environment, activating it, and then installing the necessary packages using pip. ```bash $ python3 -m venv pymyenv $ . pymyenv/bin/activate $ pip install flask-security[common] peewee ``` -------------------------------- ### MongoEngine Application Setup and Configuration Source: https://flask-security.readthedocs.io/en/stable/quickstart Demonstrates setting up a Flask application with Flask-Security and MongoEngine for user authentication. It includes database connection, defining User and Role models, and configuring security settings like secret key and password salt. ```python import os from flask import Flask, render_template_string from mongoengine import Document, connect from mongoengine.fields import ( BinaryField, BooleanField, DateTimeField, IntField, ListField, ReferenceField, StringField, ) from flask_security import Security, MongoEngineUserDatastore, \ UserMixin, RoleMixin, auth_required, hash_password, permissions_accepted # Create app app = Flask(__name__) app.config['DEBUG'] = True # Generate a nice key using secrets.token_urlsafe() app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw') # Generate a good salt for password hashing using: secrets.SystemRandom().getrandbits(128) app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634') # Don't worry if email has findable domain app.config["SECURITY_EMAIL_VALIDATOR_ARGS"] = {"check_deliverability": False} # Create database connection object db_name = "mydatabase" db = connect(alias=db_name, db=db_name, host="mongodb://localhost", port=27017) class Role(Document, RoleMixin): name = StringField(max_length=80, unique=True) description = StringField(max_length=255) permissions = ListField(required=False) meta = {"db_alias": db_name} class User(Document, UserMixin): email = StringField(max_length=255, unique=True) password = StringField(max_length=255) active = BooleanField(default=True) fs_uniquifier = StringField(max_length=64, unique=True) confirmed_at = DateTimeField() roles = ListField(ReferenceField(Role), default=[]) meta = {"db_alias": db_name} # Setup Flask-Security user_datastore = MongoEngineUserDatastore(db, User, Role) security = Security(app, user_datastore) # Views @app.route("/") @auth_required() def home(): return render_template_string("Hello {{ current_user.email }}") @app.route("/user") @auth_required() @permissions_accepted("user-read") def user_home(): return render_template_string("Hello {{ current_user.email }} you are a user!") # one time setup with app.app_context(): # Create a user and role to test with security.datastore.find_or_create_role( name="user", permissions={"user-read", "user-write"} ) if not security.datastore.find_user(email="test@me.com"): security.datastore.create_user(email="test@me.com", password=hash_password("password"), roles=["user"]) if __name__ == '__main__': # run application (can also use flask run) app.run() ``` -------------------------------- ### SQLAlchemy Install Requirements Source: https://flask-security.readthedocs.io/en/stable/quickstart This section details the prerequisites for installing Flask-Security with SQLAlchemy support, specifying the required Python version (3.10+) and the necessary pip installation commands. It outlines the steps for creating a virtual environment and installing the required packages. ```bash $ python3 -m venv pymyenv $ . pymyenv/bin/activate $ pip install flask-security[common] sqlalchemy ``` -------------------------------- ### Running Flask Applications Source: https://flask-security.readthedocs.io/en/stable/quickstart Instructions on how to run the Flask applications described in the examples. Two common methods are provided: using the `flask run` command, typically for development, or executing the Python script directly using `python app.py`. ```bash flask run ``` ```bash python app.py ``` -------------------------------- ### SQLAlchemy Database Setup and Initialization Source: https://flask-security.readthedocs.io/en/stable/quickstart Sets up a SQLAlchemy engine and session for database operations. It defines a base model and initializes the database by creating all defined tables. This is crucial for applications using SQLAlchemy as their ORM. ```python from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.ext.declarative import declarative_base from flask_security.models import sqla engine = create_engine('sqlite:////tmp/test.db') db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() # This creates the RolesUser table and is where # you would pass in non-standard tables names. sqla.FsModels.set_db_info(base_model=Base) def init_db(): # import all modules here that might define models so that # they will be registered properly on the metadata. Otherwise # you will have to import them first before calling init_db() import models Base.metadata.create_all(bind=engine) ``` -------------------------------- ### Install Flask-Security with common, MFA, and FS-SQLAlchemy Source: https://flask-security.readthedocs.io/en/stable/two_factor_configurations Installs the necessary Flask-Security packages, including common utilities, multi-factor authentication (MFA) support, and the Flask-SQLAlchemy extension. This is a prerequisite for using the provided SQLAlchemy example. ```bash python3 -m venv pymyenv . pymyenv/bin/activate pip install flask-security[common,mfa,fsqla] ``` -------------------------------- ### User Unified Sign-In Setup Source: https://flask-security.readthedocs.io/en/stable/api Methods for configuring and setting up unified sign-in for users. ```APIDOC ## POST /api/users/{user_id}/set/unified-signin ### Description Sets unified sign-in information in the user record. This method allows for pre-configuring a user for unified sign-in without requiring them to go through the setup process. It only modifies values if they are different from the existing ones. ### Method POST ### Endpoint `/api/users/{user_id}/set/unified-signin` ### Parameters #### Path Parameters - **user_id** (str) - Required - The identifier of the user. #### Request Body - **method** (str) - Required - The unified sign-in method (e.g., 'authenticator', 'sms', 'email'). - **totp_secret** (str | None) - Optional - The TOTP secret key. If not provided, the existing TOTP secret will not be changed. - **phone** (str | None) - Optional - The phone number for SMS-based unified sign-in. If not provided, the existing phone number will not be changed. ### Response #### Success Response (200) - **message** (str) - A confirmation message indicating the unified sign-in information has been set. #### Response Example ```json { "message": "Unified sign-in information has been set for the user." } ``` ``` -------------------------------- ### Install Flask-Security with Specific Extras Source: https://flask-security.readthedocs.io/en/stable/installation Installs Flask-Security along with specified optional features (extras). This allows for tailored installations based on application needs, such as database support or multi-factor authentication. ```shell pip install flask-security[extra1,extra2, ...] ``` -------------------------------- ### Running a Flask Application Source: https://flask-security.readthedocs.io/en/stable/quickstart Provides instructions on how to run a Flask application. It mentions two common methods: using the `flask run` command or executing the Python script directly using `python app.py`. ```bash flask run ``` ```bash python app.py ``` -------------------------------- ### Install Flask-Security Basic Package Source: https://flask-security.readthedocs.io/en/stable/installation Installs the core Flask-Security package and its essential dependencies. This is the fundamental step for integrating Flask-Security into a web application. ```shell pip install flask-security ``` -------------------------------- ### User Two-Factor Authentication Setup Source: https://flask-security.readthedocs.io/en/stable/api Methods for configuring and setting up two-factor authentication for users. ```APIDOC ## POST /api/users/{user_id}/set/two-factor ### Description Sets two-factor authentication information in the user record. This method allows for pre-configuring a user for two-factor authentication without requiring them to go through the setup process. It only modifies values if they are different from the existing ones. ### Method POST ### Endpoint `/api/users/{user_id}/set/two-factor` ### Parameters #### Path Parameters - **user_id** (str) - Required - The identifier of the user. #### Request Body - **primary_method** (str) - Required - The primary two-factor authentication method (e.g., 'totp', 'phone'). - **totp_secret** (str | None) - Optional - The TOTP secret key. If not provided, the existing TOTP secret will not be changed. - **phone** (str | None) - Optional - The phone number for SMS-based two-factor authentication. If not provided, the existing phone number will not be changed. ### Response #### Success Response (200) - **message** (str) - A confirmation message indicating the two-factor information has been set. #### Response Example ```json { "message": "Two-factor authentication information has been set for the user." } ``` ``` -------------------------------- ### Flask-SQLAlchemy-Lite Packaged Models Setup Source: https://flask-security.readthedocs.io/en/stable/models Illustrates the setup for Flask-Security's packaged models when using Flask-SQLAlchemy-Lite. This involves defining a base model and then incorporating the Flask-Security mixins into the User and Role models. Note the requirement for Python 3.10+. ```python from flask_security.models import sqla as sqla from flask_sqlalchemy_lite import SQLAlchemy db = SQLAlchemy(app) # Define models class Model(DeclarativeBase): pass # NOTE: call this PRIOR to declaring models sqla.FsModels.set_db_info(base_model=Model) class Role(Model, sqla.FsRoleMixin): __tablename__ = "Role" pass class User(Model, sqla.FsUserMixin): __tablename__ = "User" pass ``` -------------------------------- ### Initial Login/Registration Source: https://flask-security.readthedocs.io/en/stable/two_factor_configurations Handles the scenario where a user logs in or registers for the first time and 2FA is required. It involves an initial POST to `/login`, followed by setup via `/tf-setup`, and code validation via `/tf-validate`. ```APIDOC ## Initial Login/Registration ### Description This is basically a combination of the above two - initial POST to `/login` will return indicating that 2FA is required. The user must then POST to `/tf-setup` to setup the desired 2FA method, and finally have the user enter the code and POST to `/tf-validate`. ### Method POST ### Endpoint /login, /tf-setup, /tf-validate ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body **For initial POST to /login:** - **username** (string) - Required - The user's username. - **password** (string) - Required - The user's password. **For POST to /tf-setup:** (See Changing 2FA Setup for details on this endpoint) **For POST to /tf-validate:** (See Normal Login for details on this endpoint) ### Request Example **1. Initial Login:** ```json { "username": "newuser@example.com", "password": "newpassword" } ``` **2. Setup 2FA (after initial login indicates 2FA required):** ```json { "primary_method": "email" } ``` **3. Validate 2FA code:** ```json { "code": "654321" } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message. - **two_factor_required** (boolean) - True if 2FA is required, False otherwise. - **state_token** (string) - Returned after setup, used for code validation. #### Response Example ```json { "message": "2FA setup complete. Please validate your code.", "two_factor_required": true, "state_token": "setup_state_token" } ``` ``` -------------------------------- ### Flask-Security Two-Factor Setup Form Source: https://flask-security.readthedocs.io/en/stable/api This form is used during the two-factor authentication (2FA) setup process. It likely validates the token or code provided by the user to complete the 2FA enablement. ```python class TwoFactorSetupForm(_* args_, _** kwargs_): """The Two-factor token validation form""" pass ``` -------------------------------- ### Flask-SQLAlchemy Packaged Models Setup Source: https://flask-security.readthedocs.io/en/stable/models Shows how to integrate Flask-Security's packaged models with Flask-SQLAlchemy. It includes setting up the database instance and defining User and Role models using the provided mixins. This approach simplifies handling database migrations for various features. ```python from flask_security.models import fsqla_v3 as fsqla from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy(app) # Define models fsqla.FsModels.set_db_info(db) class Role(db.Model, fsqla.FsRoleMixin): pass class User(db.Model, fsqla.FsUserMixin): pass ``` -------------------------------- ### Basic SQLAlchemy Two-Factor Application Setup in Flask Source: https://flask-security.readthedocs.io/en/stable/two_factor_configurations Sets up a basic Flask application with Flask-SQLAlchemy and Flask-Security, configuring email and authenticator app as two-factor authentication methods. It includes user and role models, security initialization, and a simple home route. ```python import os from flask import Flask, current_app, render_template_string from flask_sqlalchemy import SQLAlchemy from flask_security import Security, SQLAlchemyUserDatastore, \ UserMixin, RoleMixin, auth_required from flask_mail import Mail # Create app app = Flask(__name__) app.config['DEBUG'] = True # Generate a nice key using secrets.token_urlsafe() app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw') # Generate a good salt for password hashing using: secrets.SystemRandom().getrandbits(128) app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634') app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://' app.config['SECURITY_TWO_FACTOR_ENABLED_METHODS'] = ['email', 'authenticator'] # 'sms' also valid but requires an sms provider app.config['SECURITY_TWO_FACTOR'] = True app.config['SECURITY_TWO_FACTOR_RESCUE_MAIL'] = "put_your_mail@gmail.com" app.config['SECURITY_TWO_FACTOR_ALWAYS_VALIDATE'] = False app.config['SECURITY_TWO_FACTOR_LOGIN_VALIDITY'] = "1 week" # Generate a good totp secret using: passlib.totp.generate_secret() app.config['SECURITY_TOTP_SECRETS'] = {"1": "TjQ9Qa31VOrfEzuPy4VHQWPCTmRzCnFzMKLxXYiZu9B"} app.config['SECURITY_TOTP_ISSUER'] = "put_your_app_name" app.config["SQLALCHEMY_ENGINE_OPTIONS"] = { "pool_pre_ping": True, } app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # Create database connection object db = SQLAlchemy(app) # Define models roles_users = db.Table('roles_users', db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) class Role(db.Model, RoleMixin): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True) description = db.Column(db.String(255)) class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(255), unique=True) # Make username unique but not required. username = db.Column(db.String(255), unique=True, nullable=True) password = db.Column(db.String(255)) active = db.Column(db.Boolean()) fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False) confirmed_at = db.Column(db.DateTime()) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) tf_phone_number = db.Column(db.String(128), nullable=True) tf_primary_method = db.Column(db.String(64), nullable=True) tf_totp_secret = db.Column(db.String(255), nullable=True) # Setup Flask-Security user_datastore = SQLAlchemyUserDatastore(db, User, Role) security = Security(app, user_datastore) mail = Mail(app) # Views @app.route('/') @auth_required() def home(): return render_template_string("Hello {{ current_user.email }}") # one time setup with app.app_context(): # Create a user to test with db.create_all() if not security.datastore.find_user(email='test@me.com'): security.datastore.create_user(email='test@me.com', password='password') db.session.commit() if __name__ == '__main__': app.run() ``` -------------------------------- ### Changing 2FA Setup Source: https://flask-security.readthedocs.io/en/stable/two_factor_configurations Allows an authenticated user to change their 2FA configuration. This involves a GET request to retrieve current settings and a POST request to `/tf-setup` to initiate changes, followed by a POST to `/tf-setup/` with a validation code. ```APIDOC ## Changing 2FA Setup ### Description An authenticated user can change their 2FA configuration (primary_method, phone number, etc.). In order to prevent a user from being locked out, the new configuration must be validated before it is stored permanently. The user starts with a GET on `/tf-setup`. This will return a list of configured 2FA methods the user can choose from, and the existing configuration. This must be followed with a POST on `/tf-setup` with the new primary method (and phone number if SMS). In the case of SMS or email, a code will be sent. In addition, a state_token will be returned in the response to the POST - this should be used to POST the code to `/tf-setup/`. In the case of setting up an authenticator app, the response to the POST will contain the QRcode image as well as the required information for manual entry. Once the code has been successfully entered, the new configuration will be permanently stored. ### Method GET, POST ### Endpoint /tf-setup, /tf-setup/ ### Parameters #### Path Parameters - **state_token** (string) - Required - The state token received after initiating the 2FA setup change. #### Query Parameters None #### Request Body **For initial POST to /tf-setup:** - **primary_method** (string) - Required - The new primary 2FA method (e.g., 'sms', 'email', 'authenticator'). - **phone_number** (string) - Optional - The phone number for SMS 2FA. **For POST to /tf-setup/:** - **code** (string) - Required - The 2FA validation code sent via SMS or email. ### Request Example **Initiating change (POST to /tf-setup):** ```json { "primary_method": "sms", "phone_number": "+1234567890" } ``` **Submitting code (POST to /tf-setup/):** ```json { "code": "123456" } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message. - **state_token** (string) - Returned after the initial POST to `/tf-setup`, used for code validation. - **qrcode** (string) - QR code image data for authenticator app setup. #### Response Example ```json { "message": "2FA setup initiated.", "state_token": "some_state_token_value" } ``` ``` -------------------------------- ### Initialization API Source: https://flask-security.readthedocs.io/en/stable/api Initializes the Flask-Security extension for a given Flask application and datastore. ```APIDOC ## init_app ### Description Initializes the Flask-Security extension for the specified application and datastore implementation. ### Method ``` init_app(_app_ , _datastore =None_, _register_blueprint =None_, _** kwargs_) ``` ### Parameters #### App Parameters - **app** (_flask.Flask_) – The application instance. - **datastore** (_UserDatastore_ | _None_) – An instance of a user datastore. Defaults to None. - **register_blueprint** (_bool_ | _None_) – Whether to register the Security blueprint. Defaults to None. - **kwargs** (_t.Any_) – Can be used to override/initialize form names or feature flags. Other kwargs are ignored. ### Return Type None ### Notes If the Security instance is created with both an `app` and `datastore`, this method should not be called explicitly, as it is invoked during the constructor. ### Properties - **mail_util**: Instance of `mail_util_cls` created at `init_app()` time. See Extendable Classes. - **mf_recovery_codes_util**: Instance of `mf_recovery_codes_util_cls` created at `init_app()` time. See Extendable Classes. - **password_util**: Instance of `password_util_cls` created at `init_app()` time. See Extendable Classes. - **phone_util**: Instance of `phone_util_cls` created at `init_app()` time. See Extendable Classes. - **totp_factory**: Instance of `Totp` created at `init_app()` time. See Extendable Classes. ``` -------------------------------- ### Nginx Reverse Proxy Configuration for Flask API Source: https://flask-security.readthedocs.io/en/stable/spa This Nginx configuration routes all API requests starting with '/api/' to a Flask backend served by Gunicorn or uWSGI. It also serves static assets directly from Nginx and handles SPA routing. This setup avoids CORS issues by keeping API calls within the same domain. ```nginx server { listen 80; server_name www.example.com; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; } location ~ ^/\(static\)/ { gzip_static on; gzip_types text/plain text/xml text/css text/comma-separated-values text/javascript application/x-javascript application/atom+xml; expires max; } error_page 500 502 503 504 /50x.html; location = /50x.html { } location /api/ { proxy_pass http://localhost:8080/api/; } location /api/ { include ..../uwsgi_params; uwsgi_pass unix:/tmp/uwsgi.sock; uwsgi_pass_header AUTHENTICATION-TOKEN; } } ``` -------------------------------- ### UserDatastore Initialization and Basic Operations Source: https://flask-security.readthedocs.io/en/stable/api Initializes the UserDatastore with user, role, and optional WebAuthn models. Supports activating, deactivating, and deleting users. Note that for session-based datastores, explicit commits are required after mutating operations. ```python from flask_security import UserDatastore # Assuming UserClass, RoleClass, WebAuthnClass are defined models user_datastore = UserDatastore(UserClass, RoleClass, WebAuthnClass) # Example: Activate a user # user_datastore.activate_user(user_object) # Example: Deactivate a user # user_datastore.deactivate_user(user_object) # Example: Delete a user # user_datastore.delete_user(user_object) ``` -------------------------------- ### Datastore Operations Source: https://flask-security.readthedocs.io/en/stable/genindex Methods for initializing and configuring the database datastore. ```APIDOC ## Datastore Operations ### Description Methods for initializing and setting up the database datastore. ### Methods #### `set_db_info()` - **Description**: Sets database information for the datastore. - **Module**: `flask_security.models.fsqla.FsModels` (class method) - **Module**: `flask_security.models.sqla.FsModels` (class method) #### `set_form_info()` - **Description**: Sets form information for the security context. - **Module**: `flask_security.Security` ``` -------------------------------- ### Get Last TOTP Counter Source: https://flask-security.readthedocs.io/en/stable/api Retrieves the last TOTP counter stored in the cache for a given user. This method is intended to be implemented by subclasses for replay-attack protection. ```python get_last_counter(_user_) Implement this to fetch stored last_counter from cache. Parameters: **user** (_UserMixin_) – User model Returns: last_counter as stored in set_last_counter() Return type: int | None ``` -------------------------------- ### Create or Find Role with Parameters Source: https://flask-security.readthedocs.io/en/stable/api Efficiently creates a role if it doesn't exist or retrieves it if it does, using the provided name and any additional keyword arguments for role creation. This simplifies role management by ensuring a role exists before operations are performed on it. ```python from flask_security import UserDatastore # Assuming UserClass, RoleClass are defined models user_datastore = UserDatastore(UserClass, RoleClass) # Example: Find or create a role with specific permissions # editor_role = user_datastore.find_or_create_role('editor', permissions=['edit_posts']) # Example: Find or create a role without additional parameters # viewer_role = user_datastore.find_or_create_role('viewer') ``` -------------------------------- ### Unified Sign-in Backward Compatibility Source: https://flask-security.readthedocs.io/en/stable/changelog Details changes related to the unified sign-in process, including redirect behavior, email authentication setup, and code sending endpoints. ```APIDOC ## Backward Compatibility Concerns: Unified Sign-in ### Description This section details specific changes in the unified sign-in functionality that may impact existing implementations. These include modifications to redirect URLs, how email-based authentication is handled, and validation checks within the sign-in process. ### Key Changes: * **Redirect Behavior**: The redirect after user setup now defaults to `/us-setup` instead of `SECURITY_US_POST_SETUP_VIEW` or `SECURITY_POST_LOGIN_VIEW`. * **Email Authentication**: One-time email link authentication is no longer automatic; it must be explicitly set up unless a user registers without a password. * **`/us-signin/send-code` Endpoint**: This endpoint now checks if the user account requires confirmation before sending a code. Previously, this check was deferred to the `/us-signin` endpoint. * **`us-verify` Endpoint**: The `code_methods` list now includes only active or set-up methods that generate a code. * **POST Only Endpoints**: `SECURITY_US_VERIFY_SEND_CODE_URL` and `SECURITY_US_SIGNIN_SEND_CODE_URL` are now exclusively POST requests. * **Password Requirement**: Empty passwords are now only permitted if `SECURITY_PASSWORD_REQUIRED` is explicitly set to `False`. * **Flash Messages**: Instead of sending `code_sent` to templates, `SECURITY_US_VERIFY_SEND_CODE_URL` and `SECURITY_US_SIGNIN_SEND_CODE_URL` now flash the `SECURITY_MSG_CODE_HAS_BEEN_SENT` message. * **Signal Arguments**: The `us_profile_changed` signal now has changed arguments for deleting sign-in methods: `method` is renamed to `methods` (a list), and a new `delete` argument indicates if an option was removed. ``` -------------------------------- ### Datastore Implementations Source: https://flask-security.readthedocs.io/en/stable/genindex Different implementations of the user datastore. ```APIDOC ## Datastore Implementations ### Description Provides various concrete implementations for user datastore management. ### Classes - **`SQLAlchemyDatastore`**: Datastore implementation using SQLAlchemy. - **`SQLAlchemySessionUserDatastore`**: User datastore implementation utilizing SQLAlchemy sessions. - **`SQLAlchemyUserDatastore`**: Core SQLAlchemy-based user datastore. ``` -------------------------------- ### SQLAlchemy Schema Alteration Example Source: https://flask-security.readthedocs.io/en/stable/changelog This snippet demonstrates how to alter a column in a SQLAlchemy schema, specifically for use with MySQL. It's a direct SQL comment indicating a database modification. ```sql # for MySQL the previous line has to be replaced with... # op.alter_column('user', 'fs_uniquifier', existing_type=sa.String(length=64), nullable=False) ``` -------------------------------- ### General Core Settings Source: https://flask-security.readthedocs.io/en/stable/configuration General configuration options for core functionalities. ```APIDOC ## General Core Settings ### SECURITY_DATETIME_FACTORY **Description**: Specifies the default datetime factory. The default is naive-UTC which corresponds to many DB’s DateTime type. **Default**: `flask_security.naive_utcnow` ``` -------------------------------- ### Add Type Hints to Flask-Security Source: https://flask-security.readthedocs.io/en/stable/changelog Starting with version 4.1.0, Flask-Security includes type hints. Note that some dependent packages may not yet have type hints, which could lead to potential type errors. ```python # Example of a function with type hints (conceptual) def get_user_email(user: User) -> str: return user.email ``` -------------------------------- ### Flask-Mail Configuration for Flask-Security Source: https://flask-security.readthedocs.io/en/stable/quickstart Configures Flask-Mail for sending emails within a Flask application integrated with Flask-Security. Requires Flask-Mail. Sets up SMTP server, port, security, and credentials. ```python # At top of file from flask_mail import Mail # After 'Create app' app.config['MAIL_SERVER'] = 'smtp.example.com' app.config['MAIL_PORT'] = 587 app.config['MAIL_USE_TLS'] = True app.config['MAIL_USERNAME'] = 'username' app.config['MAIL_PASSWORD'] = 'password' mail = Mail(app) ``` -------------------------------- ### SQLAlchemy Datastore Setting Source: https://flask-security.readthedocs.io/en/stable/configuration Configuration for optimizing role loading in SQLAlchemy Datastore. ```APIDOC ## SQLAlchemy Datastore Setting ### SECURITY_JOIN_USER_ROLES **Description**: Specifies whether to set the `UserModel.roles` loading relationship to `joined` when a `roles` attribute is present for a SQLAlchemy Datastore. Setting this to `False` restores pre 3.3.0 behavior and is required if the `roles` attribute is not a joinable attribute on the `UserModel`. The default setting improves performance by only requiring a single DB call. **Default**: `True` **Added in version**: 3.4.0 ``` -------------------------------- ### Normal Login Source: https://flask-security.readthedocs.io/en/stable/two_factor_configurations Handles the normal login flow for users who have already set up their preferred 2FA method. It starts with authentication via `/login` or `/us-signin` and, if 2FA is required, proceeds with validation via `/tf-validate`. ```APIDOC ## Normal Login ### Description In the normal case, when the user has already setup their preferred 2FA method (e.g. email, SMS, authenticator app), then the flow starts with the authentication process using the `/login` or `/us-signin` endpoints, providing their identity and password. If 2FA is required, the response will indicate that. Then, the application must POST to the `/tf-validate` with the correct code. ### Method POST ### Endpoint /login or /us-signin (for initial authentication), then /tf-validate (for 2FA code validation) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **username** (string) - Required - The user's username. - **password** (string) - Required - The user's password. ### Request Example ```json { "username": "user@example.com", "password": "securepassword" } ``` ### Response #### Success Response (200) - **message** (string) - Indicates successful login or that 2FA is required. - **two_factor_required** (boolean) - True if 2FA is required, False otherwise. #### Response Example ```json { "message": "2FA required.", "two_factor_required": true } ``` ``` -------------------------------- ### Flask-Security Two-Factor Rescue Form Source: https://flask-security.readthedocs.io/en/stable/api This form is part of the two-factor authentication (2FA) setup. It's used for a rescue mechanism, likely allowing users to regain access using a backup method if their primary 2FA device is lost or unavailable. ```python class TwoFactorRescueForm(_* args_, _** kwargs_): """The Two-factor Rescue validation form""" pass ``` -------------------------------- ### Specify User Registration Template and Redirects Source: https://flask-security.readthedocs.io/en/stable/configuration Sets the template file used for the user registration page and determines the view or URL to redirect to after a successful registration. This allows for custom registration flows and landing pages. ```python SECURITY_REGISTER_USER_TEMPLATE = "security/register_user.html" SECURITY_POST_REGISTER_VIEW = "/dashboard" ``` -------------------------------- ### Flask Application Initialization with Custom MailUtil Source: https://flask-security.readthedocs.io/en/stable/customizing This Python code demonstrates how to initialize a Flask application and integrate Flask-Security with a custom MailUtil class for email handling. It shows the typical setup involving Flask, Flask-Mailman, SQLAlchemyUserDatastore, and Flask-Security, specifically passing the custom `MyMailUtil` during security initialization. ```python from flask import Flask from flask_mailman import Mail from flask_security import Security, SQLAlchemyUserDatastore from celery import Celery # Assume User, Role, db, and MyMailUtil are defined elsewhere # from your_models import User, Role # from your_db import db # from your_mail_util import MyMailUtil mail = Mail() security = Security() cele ry = Celery() def create_app(config): """Initialize Flask instance.""" app = Flask(__name__) app.config.from_object(config) mail.init_app(app) datastore = SQLAlchemyUserDatastore(db, User, Role) security.init_app(app, datastore, mail_util_cls=MyMailUtil) return app ``` -------------------------------- ### SQLAlchemy User and Role Models Source: https://flask-security.readthedocs.io/en/stable/quickstart Defines the User and Role models for SQLAlchemy integration with Flask-Security. These models inherit from Flask-Security's mixins, providing the necessary fields and functionality for user and role management. ```python from database import Base from flask_security.models import sqla as sqla class Role(Base, sqla.FsRoleMixin): __tablename__ = 'role' class User(Base, sqla.FsUserMixin): __tablename__ = 'user' ```