Flask User
Flask User
Flask User
Release v1.0
Ling Thio
2 Well documented 5
3 Additional features 7
4 Minimal Requirements 9
5 Alternatives 11
6 Authors 13
7 Table of Contents 15
7.1 Flask-User v0.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
7.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
7.3 QuickStart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
7.4 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
7.5 Data-models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.6 Role-based Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
7.7 Customizing Flask-User . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
7.8 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
7.9 Porting v0.6 to v9.0+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
7.10 Change history . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.11 Flask-User API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.12 QuickStart App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
7.13 Basic App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
7.14 MongoDB App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
7.15 DbAdapter Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.16 View decorators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.17 EmailAdapter Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.18 Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
7.19 UserManager Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.20 UserManager Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.21 UserManager Utility methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7.22 UserManager View methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
7.23 Configuring settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
7.24 Customizing Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
i
7.25 Customizing Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.26 Advanced Customizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.27 Porting Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
7.28 Porting Customizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.29 Advanced Porting topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
7.30 Base templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
7.31 Signals (event hooking) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
7.32 Recipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
7.33 F.A.Q. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
7.34 Flask-User API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
7.35 Misc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
7.36 Customize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
ii
Flask-User Documentation, Release v1.0
Attention
So, you’re writing a Flask web application and would like to authenticate your users.
You start with a simple Login page, but soon enough you’ll need to handle:
Contents 1
Flask-User Documentation, Release v1.0
2 Contents
CHAPTER 1
3
Flask-User Documentation, Release v1.0
Well documented
• Latest documentation
• Flask-User v0.6 documentation
• Flask-User v0.5 documentation
5
Flask-User Documentation, Release v1.0
Additional features
• MIT License
• Tested on Python 2.6, 2.7, 3.3, 3.4, 3.5 and 3.6. Coverage: Over 90%.
• Event hooking – Through efficient signals.
• Support for multiple emails per user
7
Flask-User Documentation, Release v1.0
Minimal Requirements
• brypt 2.0+
• cryptography 1.6+
• Flask 0.9+
• Flask-Login 0.2+
• Flask-WTF 0.9+
• passlib 1.6+
9
Flask-User Documentation, Release v1.0
Alternatives
• Flask-Login
• Flask-Security
11
Flask-User Documentation, Release v1.0
12 Chapter 5. Alternatives
CHAPTER 6
Authors
Contributors
Many contributors
13
Flask-User Documentation, Release v1.0
14 Chapter 6. Authors
CHAPTER 7
Table of Contents
Attention
So, you’re writing a Flask web application and would like to authenticate your users.
You start with a simple Login page, but soon enough you’ll need to handle:
15
Flask-User Documentation, Release v1.0
• Latest documentation
• Flask-User v0.6 documentation
• Flask-User v0.5 documentation
• MIT License
• Tested on Python 2.6, 2.7, 3.3, 3.4, 3.5 and 3.6. Coverage: Over 90%.
• Event hooking – Through efficient signals.
• Support for multiple emails per user
• brypt 2.0+
• cryptography 1.6+
• Flask 0.9+
• Flask-Login 0.2+
• Flask-WTF 0.9+
• passlib 1.6+
7.1.5 Alternatives
• Flask-Login
• Flask-Security
7.1.6 Authors
Contributors
Many contributors
7.2 Installation
# Install Flask-User
pip install Flask-User
7.3 QuickStart
With less than a dozen lines of code, we can extend existing Flask applications with the following additional function-
ality:
• User registration with username and/or email
• Email confirmation
• User authentication (Login and Logout)
• Change username
• Change password
• Forgot password
7.2. Installation 17
Flask-User Documentation, Release v1.0
7.3.2 Flask-User-starter-app
While the example apps provide a quick way to illustrate the use of Flask-User, we do not recommend its single-file
techniques.
The Flask-User-starter-app follows typical Flask application practices using multiple files in an organized directory
structure:
app/
commands/
models/
static/
templates/
views/
tests/
See https://github.com/lingthio/Flask-User-starter-app
This may serve as a great starting place to create your next Flask application.
7.4 Limitations
We want to be transparent about what this package can and can not do.
Flask-User has been tested with Python 2.6, 2.7, 3.3, 3.4, 3.5 and 3.6.
An initialized UserManager() instance will assign itself to the app.user_manager property. This app.
user_manager name can not be changed.
User.id
User.password
User.username # optional
User.email # optional
User.email_confirmed_at # optional
User.active # optional
User.roles # optional
User.user_emails # optional
Role.name # optional
UserEmail.id # optional
UserEmail.email # optional
UserEmail.email_confirmed_at # optional
UserInvitation.id # optional
UserInvitation.email # optional
UserInvitation.invited_by_user_id # optional
If you have existing code, and are unable to globally change a fixed property name, consider using Python’s getter and
setter properties as a bridge:
7.4.7 Flexible data-model class, SQL table, and SQL column names
Here is an example of a data-model class with different class, table and column names:
7.4. Limitations 19
Flask-User Documentation, Release v1.0
# Setup Flask-User
user_manager = UserManager(app, db, Member) # Specify the Member class
self.pk1 = int(items[0])
self.pk2 = items[1]
Developers can customize the TokenManager to accept IDs without string representations.
7.5 Data-models
In its simplest form, Flask-User makes use of a single data-model class called User:
# User fields
active = db.Column(db.Boolean()),
first_name = db.Column(db.String(50), nullable=False)
last_name = db.Column(db.String(50), nullable=False)
# Setup Flask-User
user_manager = UserManager(app, db, User)
The active property is optional. Add it if your application needs to disable users. Flask-User will not let users login
if this field is set to False.
User.id
User.username # optional
User.password
7.5. Data-models 21
Flask-User Documentation, Release v1.0
User.email # optional
User.email_confirmed_at # optional
User.active # optional
User.roles # optional
User.user_emails # optional
Role.id # optional
Role.name # optional
The following property names are flexible:: UserRoles.id # optional UserRoles.user_id # optional User-
Roles.role_id # optional
If you have existing code, and are unable to globally change the fixed property names, consider using helper getters
and setters as a bridge:
SQLAlchemy allows developers to specify a database column name different from their corresponding data-model
property name like so:
The optional Role and UserRoles data-models are only required for role-based authentication. In this configura-
tion, the User data-model must aslo define a roles relationship property.
The Role data-model holds the name of each role. This name will be matched to the @roles_required function
decorator in a CASE SENSITIVE manner.
The UserRoles data-model associates Users with their Roles.
Roles are defined by adding rows to the Role table with a specific Role.name value.
admin_role = Role(name='Admin')
db.session.commit()
Users are assigned one or more roles by adding them to the User.roles property:
Flask-User can be configured to allow for multiple emails per users, pointing to the same user account and sharing the
same password. In this configuration, a separate UserEmail data-model class must be specified.
# Relationship
user_emails = db.relationship('UserEmail')
7.5. Data-models 23
Flask-User Documentation, Release v1.0
# Setup Flask-User
user_manager = UserManager(app, User, UserEmailClass=UserEmail)
The is_primary property defines which email receives account notification emails.
[TBD]
Authorization is the process of specifying and enforcing access rights of users to resources.
Flask-User offers role-based authorization through the use of the @roles_required decorator.
7.6.1 @roles_required
Note: Comparison of role names is case sensitive, so 'Admin' will NOT match 'admin'.
The @roles_required decorator accepts one or more role names. At the decorator level, if multiple role names are
specified here, the user must have all the specified roles. This is the AND operation.
At the argument level, each item may be a role name or a list or role names. If a list of role names is specified here,
the user mast have any one of the specified roles to gain access. This is the OR operation.
In the example below, the user must always have the 'Starving' role, AND either the 'Artist' role OR the
'Programmer' role:
Note: The nesting level only goes as deep as this example shows.
The @roles_required decorator depends the Role and UserRoles data-models (in addition to the User data-
model).
See the docs on Role and UserRoles data-models.
From the very beginning, Flask-User was specifically designed to be fully customizable in addition to being secure
and reliable.
• Flask-User can be configured through Configuring settings.
– Enabling and disabling of features
– General settings
– Token expiration settings
– Complete control of Passlib’s password hash settings
– Form URLs
– Form template file paths
– Email template file paths
• Customizing Forms
– Form Templates
– Customizing Form Classes
– Customizing Form Validators
– Customizing Form Views
• Customizing Emails
– Customizing Email templates
• And then there are Advanced Customizations
– Customizing the Email, Password and Token Managers
– Implementing a CustomDbAdapter
– Implementing a CustomEmailAdapter
7.8 Internationalization
There are two distinct Flask extensions for managing translations: Flask-Babel and Flask-BabelEx.
Flask-User relies on the domain-specific abilities of Flask-BabelEx and will not translate with Flask-Babel:
# Install Flask-BabelEx
pip intall Flask-BabelEx
Example:
You will need to add and prioritize one of the Flask-User supported languages in your browser.
For Google Chrome:
• Chrome > Preferences. Search for ‘Language’.
• Expand the ‘Language’ bar > Add languages.
• Check the ‘Dutch’ checkbox > Add.
• Make sure to move it to the top: Three dots > Move to top.
You can test this with the Basic App.
Ever since Flask-User v0.4, we had plans to improve Flask-User but were held back by our desire to maintain back-
wards compatibility for a while.
With Flask-User v1.0 (and its v0.9 alpha/beta) we decided it was time to move forward, breaking compatibility with
v0.6.
If you have:
• Specified custom form classes (the .py files)
• Specified custom view functions
• Specified custom password or username validators
• Specified a custom TokenManager
• Used the optional UserAuth class
you will also need to read: Porting Customizations.
With v0.9 (alpha and beta) and v1.0 (stable) we simplified customization by allowing developers to override or
extend UserManager properties and methods.
We increased security by having the TokenManager accept parts of passwords, in addition to the user ID, to invalidate
tokens after a password has changed. The TokenManager now also excepts IDs other than small integers.
Hashlib password hashing is completely configurable through two config settings:
USER_PASSLIB_CRYPTCONTEXT_SCHEMES and USER_PASSLIB_CRYPTCONTEXT_KEYWORDS.
Example: SCHEMES=['bcrypt', 'argon2'], KEYWORDS=dict(bcrypt__rounds=12,
argon2__memory_cost=512).
We added support for MongoDBs (through Flask-MongoEngine) and for DynamoDBs (through Flask-Flywheel).
We introduced the EmailAdapter interface to support sending emails not only via SMTP, but also via sendmail,
SendGrid, and custom EmailAdapters.
For all of the above we finally had to break compatibility with v0.6 (stable). For non-customized Flask-User apps, the
porting is relatively straightforward. See the ‘Porting from v0.6 to v0.9+’ section in our docs.
• v0.9.0 - First 1.0 alpha release
• v0.6.* - No longer compatible
• UserManager Class
• UserManager Settings
• UserManager Utility methods
• UserManager View methods
• View decorators
• Forms
• DBManager class
• EmailManager class
• PasswordManager class
• TokenManager class
• DbAdapter Interface
• EmailAdapter Interface
get_primary_user_email(user)
Retrieve the email from User object or the primary UserEmail object (if multiple emails per user are
enabled).
get_user_and_user_email_by_id(user_or_user_email_id)
Retrieve the User and UserEmail object by ID.
get_user_and_user_email_by_email(email)
Retrieve the User and UserEmail object by email address.
get_user_by_id(id)
Retrieve a User object by ID.
get_user_email_by_id(id)
Retrieve a UserEmail object by ID.
get_user_invitation_by_id(id)
Retrieve a UserInvitation object by ID.
get_user_roles(user)
Retrieve a list of user role names.
save_object(object)
Save an object to the database.
save_user_and_user_email(user, user_email)
Save the User and UserEmail object.
user_has_confirmed_email(user)
Returns True if new_username does not exist or belongs to the current user.
Return False otherwise.
create_all_tables()
Create database tables for all known database data-models.
drop_all_tables()
Drop all tables.
Warning: ALL DATA WILL BE LOST. Use only for automated testing.
Example
password_manager = PasswordManager('bcrypt')
hash_password(password)
Hash plaintext password using the password_hash specified in the constructor.
Parameters password (str) – Plaintext password that the user types in.
Returns hashed password.
Example
user.password = hash_password('mypassword')
verify_password(password, password_hash)
Verify plaintext password against hashed password.
Parameters
• password (str) – Plaintext password that the user types in.
• password_hash (str) – Password hash generated by a previous call to
hash_password().
Returns
Example
if verify_password('mypassword', user.password):
login_user(user)
See also:
Customizing the PasswordManager.
The TokenManager generates and verifies timestamped, signed and encrypted tokens.
These tokens are used in the following places:
• To securely store User IDs in the browser session cookie.
• To provide secure tokens in email-confirmation emails.
• To provide secure tokens in reset-password emails.
class TokenManager(app)
Generate and verify timestamped, signed and encrypted tokens.
Check config settings and initialize the Fernet encryption cypher.
Fernet is basically AES128 in CBC mode, with a timestamp and a signature.
Parameters app (Flask) – The Flask application instance.
generate_token(*args)
Convert a list of integers or strings, specified by *args, into an encrypted, timestamped, and signed token.
Note: strings may not contain any '|' characters, nor start with a '~' character as these are used as
separators and integer indicators for encoding.
Example:
verify_token(token, expiration_in_seconds)
Verify token signature, verify token expiration, and decrypt token.
Implemented as:
Example:
# Verify that a User with ``user_id`` has a password that ends in ``password_
˓→ends_with``.
token_is_valid = False
data_items = token_manager.verify(token, expiration_in_seconds)
if data_items:
user_id = data_items[0]
password_ends_with = data_items[1]
user = user_manager.db_manager.get_user_by_id(user_id)
token_is_valid = user and user.password[-8:]==password_ends_with
encrypt_string(concatenated_str)
Timestamp, sign and encrypt a string into a token using cryptography.fernet.Fernet().
decrypt_string(token_str, expiration_in_seconds)
Verify signature, verify timestamp, and decrypt a token using cryptography.fernet.Fernet().
encode_data_items(*args)
Encodes a list of integers and strings into a concatenated string.
• encode string items as-is.
• encode integer items as base-64 with a '~' prefix.
• concatenate encoded items with a '|' separator.
Example
Example
Example
Example
The QuickStart App allows users to register and login with a username and avoids the need to configure SMTP settings.
11
16 # Flask settings
17 SECRET_KEY = 'This is an INSECURE secret!! DO NOT use this in production!!'
18
19 # Flask-SQLAlchemy settings
20 SQLALCHEMY_DATABASE_URI = 'sqlite:///quickstart_app.sqlite' # File-based SQL
˓→database
23 # Flask-User settings
24 USER_APP_NAME = "Flask-User QuickStart App" # Shown in and email templates
˓→and page footers
29
30 def create_app():
31 """ Flask application factory """
32
37 # Initialize Flask-SQLAlchemy
38 db = SQLAlchemy(app)
39
46
52 # User information
53 first_name = db.Column(db.String(100), nullable=False, server_default='')
54 last_name = db.Column(db.String(100), nullable=False, server_default='')
55
78 # The Members page is only accessible to authenticated users via the @login_
˓→required decorator
79 @app.route('/members')
80 @login_required # User must be authenticated
81 def member_page():
82 # String-based templates
83 return render_template_string("""
84 {% extends "flask_user_layout.html" %}
85 {% block content %}
86 <h2>Members page</h2>
87 <p><a href={{ url_for('user.register') }}>Register</a></p>
88 <p><a href={{ url_for('user.login') }}>Sign in</a></p>
89 <p><a href={{ url_for('home_page') }}>Home page</a> (accessible to
˓→anyone)</p>
95 return app
96
97
cd ~/dev/my_app
python quickstart_app.py
7.12.5 Troubleshooting
If you receive a SQLAlchemy error message, delete the quickstart_app.sqlite file and restart the app. You may be
using an old DB schema in that file.
The Basic App builds on the QuickStart App by adding the following features:
• Register and Login with an email
• Confirm emails, Change passwords
• Role-base authorization
• Enable translations
Unlike the QuickStart App, the Basic App requires proper SMTP settings and the installation of Flask-BabelEx.
7 import datetime
8 from flask import Flask, request, render_template_string
9 from flask_babelex import Babel
10 from flask_sqlalchemy import SQLAlchemy
11 from flask_user import current_user, login_required, roles_required, UserManager,
˓→UserMixin
12
13
18 # Flask settings
19 SECRET_KEY = 'This is an INSECURE secret!! DO NOT use this in production!!'
20
21 # Flask-SQLAlchemy settings
22 SQLALCHEMY_DATABASE_URI = 'sqlite:///basic_app.sqlite' # File-based SQL
˓→database
35 # Flask-User settings
36 USER_APP_NAME = "Flask-User Basic App" # Shown in and email templates and
˓→page footers
42
43 def create_app():
44 """ Flask application factory """
45
50 # Initialize Flask-BabelEx
51 babel = Babel(app)
52
53 # Initialize Flask-SQLAlchemy
54 db = SQLAlchemy(app)
55
62
68 # User information
69 first_name = db.Column(db.String(100), nullable=False, server_default='')
70 last_name = db.Column(db.String(100), nullable=False, server_default='')
71
87
129 {% endblock %}
130 """)
131
146 {% endblock %}
147 """)
148
163 {% endblock %}
164 """)
165
168
• Lines 25-33 configure Flask-Mail. Make sure to use the correct settings or emails will not be sent.
Note: Gmail and Yahoo mail nowadays disable SMTP requests by default. Search the web for ‘Gmail less secure
apps’ or ‘Yahoo less secure apps’ to learn how to change this default setting for your account.
See QuickStart App for an example without SMTP.
If you want to see translation in action, you will need to change and prioritize a supported language (one that is other
than ‘English’) in your browser language preferences.
For Google Chrome:
• Chrome > Preferences. Search for ‘Language’.
• Expand the ‘Language’ bar > Add languages.
• Check the ‘Dutch’ checkbox > Add.
• Make sure to move it to the top: Three dots > Move to top.
cd ~/dev/my_app
python basic_app.py
7.13.7 Troubleshooting
If you receive an EmailError message, or if the Registration form does not respond quickly then you may have specified
incorrect SMTP settings.
If you receive a SQLAlchemy error message, you may be using an old DB schema. Delete the quickstart_app.sqlite
file and restart the app.
If you don’t see any translations, you may not have installed Flask-BabelEx, or you may not have prioritized a
supported language in your browser settings.
Flask-User can work with MongoDB databases by replacing the default SQLDbAdapter with the provided MongoD-
bAdapter.
The MONGODB_SETTINGS in this example requires a MongoDB server running on localhost:27017 (its default).
# Install Flask-User
pip install flask-user
# Install Flask-MongoEngine
pip install Flask-MongoEngine
11
13 class ConfigClass(object):
14 """ Flask application config """
15
16 # Flask settings
17 SECRET_KEY = 'This is an INSECURE secret!! DO NOT use this in production!!'
18
19 # Flask-MongoEngine settings
20 MONGODB_SETTINGS = {
21 'db': 'tst_app',
22 'host': 'mongodb://localhost:27017/tst_app'
23 }
24
25 # Flask-User settings
26 USER_APP_NAME = "Flask-User MongoDB App" # Shown in and email templates and
˓→page footers
31
32 def create_app():
33 """ Flask application factory """
34
39 # Setup Flask-MongoEngine
40 db = MongoEngine(app)
41
51 # User information
52 first_name = db.StringField(default='')
53 last_name = db.StringField(default='')
54
55 # Relationships
56 roles = db.ListField(db.StringField(), default=[])
57
77 # The Members page is only accessible to authenticated users via the @login_
˓→required decorator
78 @app.route('/members')
79 @login_required # User must be authenticated
80 def member_page():
81 # String-based templates
82 return render_template_string("""
83 {% extends "flask_user_layout.html" %}
84 {% block content %}
85 <h2>Members page</h2>
86 <p><a href={{ url_for('user.register') }}>Register</a></p>
87 <p><a href={{ url_for('user.login') }}>Sign in</a></p>
88 <p><a href={{ url_for('home_page') }}>Home page</a> (accessible to
˓→anyone)</p>
94 return app
95
96
cd ~/dev/my_app
python mongodb_app.py
7.14.5 Troubleshooting
[TBD]
The DbAdapterInterface class defines an interface to find, add, update and remove persistent database objects, while
shielding the Flask-User code from the underlying implementation.
class DbAdapterInterface(app, db)
Define the DbAdapter interface to manage objects in various databases.
This interface supports session-based ODMs (db.session.add()/commit()) as well as object-based
ODMs (object.save()).
Parameters
• app (Flask) – The Flask appliation instance.
• db – The object-database mapper instance.
__init__(app, db)
Parameters
• app (Flask) – The Flask appliation instance.
• db – The object-database mapper instance.
add_object(object)
Add a new object to the database.
commit()
Save all modified session objects to the database.
delete_object(object)
Delete object from database.
find_objects(ObjectClass, **kwargs)
Retrieve all objects of type ObjectClass, matching the specified filters in **kwargs – case sensitive.
find_first_object(ObjectClass, **kwargs)
Retrieve the first object of type ObjectClass, matching the specified filters in **kwargs – case sen-
sitive.
get_object(ObjectClass, id)
Retrieve object of type ObjectClass by id.
save_object(object)
Save object to database.
create_all_tables()
Create database tables for all known database data-models.
drop_all_tables()
Drop all tables.
Warning: ALL DATA WILL BE LOST. Use only for automated testing.
You can write you own DbAdapter implementation by defining a CustomDbAdapter class and configure Flask-User
to use this class like so:
# Define a CustomDbAdapter
from flask_user.db_adapters import DbAdapterInterface
class CustomDbAdapter(DbAdapterInterface):
...
# Setup Flask-User
user_manager = UserManager(app, db, User)
# Customize Flask-User
user_manager.db_adapter = CustomDbAdapter(app)
Flask-User view decorators serve as the gatekeepers to prevent unauthenticated or unauthorized users from accessing
certain views.
Important: The @route decorator must always be the first view decorator in a list of view decorators (because it’s
used to map the function below itself to a URL).
login_required(view_function)
This decorator ensures that the current user is logged in.
Example:
@route('/member_page')
@login_required
def member_page(): # User must be logged in
...
Calls unauthorized_view() when the user is not logged in or when the user has not confirmed their email
address.
Calls the decorated view otherwise.
roles_accepted(*role_names)
@route('/edit_article')
@roles_accepted('Writer', 'Editor')
def edit_article(): # User must be 'Writer' OR 'Editor'
...
Calls unauthenticated_view() when the user is not logged in or when user has not confirmed their email
address.
Calls unauthorized_view() when the user does not have the required roles.
Calls the decorated view otherwise.
roles_required(*role_names)
@route('/escape')
@roles_required('Special', 'Agent')
def escape_capture(): # User must be 'Special' AND 'Agent'
...
Calls unauthenticated_view() when the user is not logged in or when user has not confirmed their email
address.
Calls unauthorized_view() when the user does not have the required roles.
Calls the decorated view otherwise.
allow_unconfirmed_email(view_function)
This decorator ensures that the user is logged in, but allows users with or without a confirmed email addresses
to access this particular view.
It works in tandem with the USER_ALLOW_LOGIN_WITHOUT_CONFIRMED_EMAIL=True setting.
Caution:
Use USER_ALLOW_LOGIN_WITHOUT_CONFIRMED_EMAIL=True and
@allow_unconfirmed_email with caution, as they relax security requirements.
Make sure that decorated views never call other views directly. Allways use redirect() to ensure
proper view protection.
Example:
@route('/show_promotion')
@allow_unconfirmed_emails
def show_promotion(): # Logged in, with or without
... # confirmed email address
@route('/show_promotion')
@allow_unconfirmed_emails
@roles_required('Visitor')
def show_promotion(): # Logged in, with or without
... # confirmed email address
The EmailAdapterInterface class defines an interface to send email messages while shielding the Flask-User code from
the underlying implementation.
class EmailAdapterInterface(app)
Define the EmailAdapter interface to send emails through various email services.
Parameters app (Flask) – The Flask application instance.
__init__(app)
Parameters app (Flask) – The Flask application instance.
send_email_message(recipient, subject, html_message, text_message, sender_email, sender_name)
Send email message via an email mailer.
Parameters
• recipient – Email address or tuple of (Name, Email-address).
• subject – Subject line.
• html_message – The message body in HTML.
• text_message – The message body in plain text.
Tip:
def send_email_message(...):
# use self.sender_name and self.sender_email here...
You can write you own EmailAdapter implementation by defining a CustomEmailAdapter class and configure Flask-
User to use this class like so:
# Define a CustomEmailAdapter
from flask_user.email_adapters import EmailAdapterInterface
class CustomEmailAdapter(EmailAdapterInterface):
...
# Setup Flask-User
user_manager = UserManager(app, db, User)
# Customize Flask-User
user_manager.email_adapter = CustomDbAdapter(app)
7.18 Forms
7.18.1 AddEmailForm
7.18.2 ChangeUsernameForm
7.18.3 EditUserProfileForm
7.18.4 ForgotPasswordForm
7.18.5 InviteUserForm
7.18.6 LoginForm
7.18.7 RegisterForm
7.18.8 ResendEmailConfirmationForm
7.18.9 ResetPasswordForm
Example
customize(app)
Override this method to customize properties.
Example:
# Customize Flask-User
class CustomUserManager(UserManager):
# Setup Flask-User
user_manager = CustomUserManager(app, db, User)
password_validator(form, field)
Ensure that passwords have one lowercase letter, one uppercase letter and one digit.
Override this method to customize the password validator.
username_validator(form, field)
Ensure that Usernames contains at least 3 alphanumeric characters.
Override this method to customize the username validator.
See also:
• UserManager Settings
• UserManager View methods
• UserManager Utility methods
class UserManager__Settings
Flask-User settings and their defaults.
Feature settings
USER_ENABLE_EMAIL = True
Allow users to associate multiple email addresses with one user account.
Depends on USER_ENABLE_EMAIL=True
USER_ENABLE_USERNAME = True
USER_APP_NAME = 'USER_APP_NAME'
The application name displayed in email templates and page template footers.
USER_AUTO_LOGIN = True
Automatic sign-in if the user session has not expired.
USER_AUTO_LOGIN_AFTER_CONFIRM = True
Automatic sign-in after a user confirms their email address.
USER_AUTO_LOGIN_AFTER_REGISTER = True
Automatic sign-in after a user registers.
USER_AUTO_LOGIN_AFTER_RESET_PASSWORD = True
Automatic sign-in after a user resets their password.
USER_AUTO_LOGIN_AT_LOGIN = True
Automatic sign-in at the login form (if the user session has not expired).
USER_EMAIL_SENDER_EMAIL = ''
Ensure that users can login only with a confirmed email address.
Depends on USER_ENABLE_EMAIL=True.
This setting works in tandem with the @allow_unconfirmed_emails view decorator to allow users
without confirmed email addresses to access certain views.
Caution:
Use USER_ALLOW_LOGIN_WITHOUT_CONFIRMED_EMAIL=True and
@allow_unconfirmed_email with caution, as they relax security requirements.
Make sure that decorated views never call other views directly. Allways se redirect() to ensure
proper view protection.
USER_REQUIRE_RETYPE_PASSWORD = True
Show ‘Email does not exist’ message instead of ‘Incorrect Email or password’.
Depends on USER_ENABLE_EMAIL=True.
USER_SHOW_USERNAME_DOES_NOT_EXIST = False
Show ‘Username does not exist’ message instead of ‘Incorrect Username or password’.
Depends on USER_ENABLE_USERNAME=True.
USER_CONFIRM_EMAIL_EXPIRATION = 172800
USER_PASSLIB_CRYPTCONTEXT_SCHEMES = ['bcrypt']
USER_CHANGE_PASSWORD_TEMPLATE = 'flask_user/change_password.html'
USER_CHANGE_USERNAME_TEMPLATE = 'flask_user/change_username.html'
USER_EDIT_USER_PROFILE_TEMPLATE = 'flask_user/edit_user_profile.html'
USER_FORGOT_PASSWORD_TEMPLATE = 'flask_user/forgot_password.html'
USER_INVITE_USER_TEMPLATE = 'flask_user/invite_user.html'
USER_LOGIN_TEMPLATE = 'flask_user/login.html'
USER_MANAGE_EMAILS_TEMPLATE = 'flask_user/manage_emails.html'
USER_REGISTER_TEMPLATE = 'flask_user/register.html'
USER_RESEND_CONFIRM_EMAIL_TEMPLATE = 'flask_user/resend_confirm_email.html'
USER_RESET_PASSWORD_TEMPLATE = 'flask_user/reset_password.html'
USER_CONFIRM_EMAIL_TEMPLATE = 'flask_user/emails/confirm_email'
USER_INVITE_USER_EMAIL_TEMPLATE = 'flask_user/emails/invite_user'
USER_PASSWORD_CHANGED_EMAIL_TEMPLATE = 'flask_user/emails/password_changed'
USER_REGISTERED_EMAIL_TEMPLATE = 'flask_user/emails/registered'
USER_RESET_PASSWORD_EMAIL_TEMPLATE = 'flask_user/emails/reset_password'
USER_USERNAME_CHANGED_EMAIL_TEMPLATE = 'flask_user/emails/username_changed'
USER_AFTER_CHANGE_PASSWORD_ENDPOINT = ''
USER_AFTER_CHANGE_USERNAME_ENDPOINT = ''
USER_AFTER_CONFIRM_ENDPOINT = ''
USER_AFTER_EDIT_USER_PROFILE_ENDPOINT = ''
USER_AFTER_FORGOT_PASSWORD_ENDPOINT = ''
USER_AFTER_LOGIN_ENDPOINT = ''
USER_AFTER_LOGOUT_ENDPOINT = ''
USER_AFTER_REGISTER_ENDPOINT = ''
USER_AFTER_RESEND_EMAIL_CONFIRMATION_ENDPOINT = ''
USER_AFTER_RESET_PASSWORD_ENDPOINT = ''
USER_AFTER_INVITE_ENDPOINT = ''
USER_UNAUTHENTICATED_ENDPOINT = 'user.login'
USER_UNAUTHORIZED_ENDPOINT = ''
See also:
• UserManager Class
• UserManager View methods
• UserManager Utility methods
class UserManager__Utils
Flask-User utility methods.
call_or_get(function_or_property)
if self.call_or_get(current_user.is_authenticated):
pass
email_is_available(new_email)
Check if new_email is available.
Returns True if new_email does not exist or belongs to the current user.
Return False otherwise.
generate_token(*args)
Convenience method that calls self.token_manager.generate_token(*args).
hash_password(password)
Convenience method that calls self.password_manager.hash_password(password).
make_safe_url(url)
Makes a URL safe by removing optional hostname and port.
Example
make_safe_url('https://hostname:80/path1/path2?q1=v1&q2=v2#fragment')
returns '/path1/path2?q1=v1&q2=v2#fragment'
class UserManager__Views
Flask-User views.
change_password_view(*args, **kwargs)
Prompt for old password and new password and change the user’s password.
change_username_view(*args, **kwargs)
Prompt for new username and old password and change the user’s username.
confirm_email_view(token)
Verify email confirmation token and activate the user account.
email_action_view(*args, **kwargs)
Perform action ‘action’ on UserEmail object ‘id’
forgot_password_view()
Prompt for email and send reset password email.
invite_user_view(*args, **kwargs)
Allows users to send invitations to register an account
login_view()
Prepare and process the login form.
logout_view()
Process the logout link.
register_view()
Display registration form and create new User.
resend_email_confirmation_view()
Prompt for email and re-send email conformation email.
reset_password_view(token)
Verify the password reset token, Prompt for new password, and set the user’s password.
unauthenticated_view()
Prepare a Flash message and redirect to USER_UNAUTHENTICATED_ENDPOINT
unauthorized_view()
Prepare a Flash message and redirect to USER_UNAUTHORIZED_ENDPOINT
See also:
• UserManager Class
• UserManager Settings
• UserManager Utility methods
Flask-User default features and settings can overridden through the app config:
Feature settings
USER_ENABLE_EMAIL = True
Allow users to associate multiple email addresses with one user account.
Depends on USER_ENABLE_EMAIL=True
USER_ENABLE_USERNAME = True
USER_APP_NAME = 'USER_APP_NAME'
The application name displayed in email templates and page template footers.
USER_AUTO_LOGIN = True
Automatic sign-in if the user session has not expired.
USER_AUTO_LOGIN_AFTER_CONFIRM = True
Automatic sign-in after a user confirms their email address.
USER_AUTO_LOGIN_AFTER_REGISTER = True
Automatic sign-in after a user registers.
USER_AUTO_LOGIN_AFTER_RESET_PASSWORD = True
Automatic sign-in after a user resets their password.
USER_AUTO_LOGIN_AT_LOGIN = True
Automatic sign-in at the login form (if the user session has not expired).
USER_EMAIL_SENDER_EMAIL = ''
Ensure that users can login only with a confirmed email address.
Depends on USER_ENABLE_EMAIL=True.
This setting works in tandem with the @allow_unconfirmed_emails view decorator to allow users
without confirmed email addresses to access certain views.
Caution:
Use USER_ALLOW_LOGIN_WITHOUT_CONFIRMED_EMAIL=True and
@allow_unconfirmed_email with caution, as they relax security requirements.
Make sure that decorated views never call other views directly. Allways se redirect() to ensure
proper view protection.
USER_REQUIRE_RETYPE_PASSWORD = True
Show ‘Email does not exist’ message instead of ‘Incorrect Email or password’.
Depends on USER_ENABLE_EMAIL=True.
USER_SHOW_USERNAME_DOES_NOT_EXIST = False
Show ‘Username does not exist’ message instead of ‘Incorrect Username or password’.
Depends on USER_ENABLE_USERNAME=True.
USER_CONFIRM_EMAIL_EXPIRATION = 172800
USER_PASSLIB_CRYPTCONTEXT_SCHEMES = ['bcrypt']
USER_CHANGE_PASSWORD_TEMPLATE = 'flask_user/change_password.html'
USER_CHANGE_USERNAME_TEMPLATE = 'flask_user/change_username.html'
USER_EDIT_USER_PROFILE_TEMPLATE = 'flask_user/edit_user_profile.html'
USER_FORGOT_PASSWORD_TEMPLATE = 'flask_user/forgot_password.html'
USER_INVITE_USER_TEMPLATE = 'flask_user/invite_user.html'
USER_LOGIN_TEMPLATE = 'flask_user/login.html'
USER_MANAGE_EMAILS_TEMPLATE = 'flask_user/manage_emails.html'
USER_REGISTER_TEMPLATE = 'flask_user/register.html'
USER_RESEND_CONFIRM_EMAIL_TEMPLATE = 'flask_user/resend_confirm_email.html'
USER_RESET_PASSWORD_TEMPLATE = 'flask_user/reset_password.html'
USER_CONFIRM_EMAIL_TEMPLATE = 'flask_user/emails/confirm_email'
USER_INVITE_USER_EMAIL_TEMPLATE = 'flask_user/emails/invite_user'
USER_PASSWORD_CHANGED_EMAIL_TEMPLATE = 'flask_user/emails/password_changed'
USER_REGISTERED_EMAIL_TEMPLATE = 'flask_user/emails/registered'
USER_RESET_PASSWORD_EMAIL_TEMPLATE = 'flask_user/emails/reset_password'
USER_USERNAME_CHANGED_EMAIL_TEMPLATE = 'flask_user/emails/username_changed'
USER_AFTER_CHANGE_PASSWORD_ENDPOINT = ''
USER_AFTER_CHANGE_USERNAME_ENDPOINT = ''
USER_AFTER_CONFIRM_ENDPOINT = ''
USER_AFTER_EDIT_USER_PROFILE_ENDPOINT = ''
USER_AFTER_FORGOT_PASSWORD_ENDPOINT = ''
USER_AFTER_LOGIN_ENDPOINT = ''
USER_AFTER_LOGOUT_ENDPOINT = ''
USER_AFTER_REGISTER_ENDPOINT = ''
USER_AFTER_RESEND_EMAIL_CONFIRMATION_ENDPOINT = ''
USER_AFTER_RESET_PASSWORD_ENDPOINT = ''
USER_AFTER_INVITE_ENDPOINT = ''
USER_UNAUTHENTICATED_ENDPOINT = 'user.login'
USER_UNAUTHORIZED_ENDPOINT = ''
To keep the code base simple and robust, we offer no easy way to change the ‘/user’ base URLs or the ‘/flask_user’
base directories in bulk. Please copy them from this page, then use your editor to bulk-change these settings.
Flask-User ships with the following EmailAdapters: - SendgridEmailAdapter to send email messages via Sendgrid -
SendmailEmailAdapter to send email messages via Sendmail - SMTPEmailAdapter to send email messages via SMTP
Flask-User works with the SMTPEmailAdapter by default, but another EmailAdapter can be configured like so:
# Setup Flask-User
user_manager = UserManager(app, db, User)
# Customize Flask-User
from flask_user.email_adapters import SendgridEmailAdapter
user_manager.email_adapter = SendgridEmailAdapter(app)
Emails are constructed using three email template files, using the Jinja2 templating engine. The ‘registered’ email, for
example, makes use of the following template files:
base_subject.txt
base_message.html
base_message.txt
The base templates are shared across all message types. Typically the base templates define the message design (the
look-and-feel) while the message templates define the message content.
Before we can customize any of the email templates, we’ll need to copy them from the Flask-User install directory to
your application’s template directory.
# IMPORTANT:
# If you've already worked on customizing form templates, you can (and must) skip
˓→this step,
# since you've already copied the email templates along with the form templates.
cp ~/.envs/my_app/lib/python2.7/site-packages/flask_user/templates/flask_user ~/
˓→dev/my_app/app/templates/.
cp ~/.envs/my_app/lib/python2.7/site-packages/flask_user/templates/flask_user_
˓→base.html ~/dev/my_app/app/templates/.
ls -1 ~/dev/my_app/app/templates/flask_user/emails
Expected output:
base_message.html
base_message.txt
base_subject.txt
confirm_email_message.html
confirm_email_message.txt
confirm_email_subject.txt
...
After you’ve copied the Email template files <CopyEmailTemplateFiles>, you can edit any HTML or TXT template
file in your app/templates/flask_user/emails/ directory, and change it to your liking.
Flask-User makes the following template variables available to all email templates:
app_name # The value of the USER_APP_NAME app config setting
email # The user's email
user # The user's User object
user_manager # The UserManager object
The following email templates also receive the following template variables:
# confirm_email templates
confirm_email_link # Confirm email link with confirm email token
# forgot_password templates
reset_password_link # Reset password link with reset password token
# invite_user templates
accept_invitation_link # Accept invitation like with register token
invited_by_user # The user that created this invitation
Before we can customize any of the form templates, we’ll need to copy them from the Flask-User install directory to
your application’s template directory.
# since you've already copied the form templates along with the email templates.
cp ~/.envs/my_app/lib/python2.7/site-packages/flask_user/templates/flask_user ~/
˓→dev/my_app/app/templates/.
cp ~/.envs/my_app/lib/python2.7/site-packages/flask_user/templates/flask_user_
˓→base.html ~/dev/my_app/app/templates/.
Expected output:
_authorized_base.html
_common_base.html
_macros.html
_public_base.html
change_password.html
change_username.html
emails
...
After you’ve copied the Form template files, you can edit any template file in your app/templates/
flask_user/ directory, and change it to your liking.
All Flask-User templates extend from app/template/flask_user_layout.html. You can configure all
Flask-User templates to extend from your own layout template by:
editing app/template/flask_user/_common_base.html, and
replacing:
{% extends "flask_user_layout.html" %}
with:
{% extends "layout.html" %}
Optionally, if you need to add form fields to a Flask-User form, you will need to customize that form like so:
# Customize the User class
class User(db.Model, UserMixin):
...
country = db.Column(db.String(100), nullable=False)
# Customize Flask-User
class CustomUserManager(UserManager):
# Setup Flask-User
user_manager = CustomUserManager(app, db, User)
See also:
Forms shows a complete list of customizable forms.
Default forms are defined here
Note: Notice that in a simple use case like this, the form will work without customizing the accompanying view
method. This is because WTForm’s populate_obj() function knows how to move data from form.country.
data to user.country (as long as the property names are identical).
Flask user ships with default username and password form field validators that can be customized like so:
from wtforms import ValidationError
# Customize Flask-User
class CustomUserManager(UserManager):
# Setup Flask-User
user_manager = CustomUserManager(app, db, User)
Examples:
The default password_validator().
The default username_validator().
View methods contain the code that prepares forms (on an HTTP GET) and process forms (on an HTTP POST).
Optionally, if you want to change the default behaviour, you can customize the view methods like so:
# Customize Flask-User
class CustomUserManager(UserManager):
# Setup Flask-User
user_manager = CustomUserManager(app, db, User)
Warning: View methods perform lots of intricate operations, so use this feature with caution. Be sure to read the
source code of the default view method and make sure you understand all that it does before attempting to modify
its behavior.
Default view methods are defined here
See also:
UserManager View methods for a complete list of customizable view methods.
Developers can customize the EmailManager, the PasswordManager, and the TokenManager as follows:
# Customize the EmailManager
from flask_user import EmailManager
class CustomEmailManager(EmailManager):
...
# Setup Flask-User
user_manager = UserManager(app, db, User)
See also:
EmailManager class,
PasswordManager class, and
TokenManager class.
Use: pip freeze | grep Flask-User to show the installed Flask-User version, and update your require-
ments.txt file accordingly:
# In requirements.txt:
Flask-User==0.9.{X}
We’ve removed the need to specify the type of DbAdapter during application setup.
From v0.6:
To v0.9+:
Make sure to stop using the legacy SQLAlchemyAdapter or DbAdapter classes as they will trigger legacy warning
exceptions.
Some v0.6 USER_... settings have been renamed in v0.9 to better reflect what these settings means. v0.9 still honors
the old v0.6 names, but a deprecation warning message will be printed.
We recommend resolving these warning messages by renaming the following settings:
Replace: USER_ENABLE_RETYPE_PASSWORD
with: USER_REQUIRE_RETYPE_PASSWORD
Replace: USER_ENABLE_LOGIN_WITHOUT_CONFIRM_EMAIL
with: USER_ALLOW_LOGIN_WITHOUT_CONFIRMED_EMAIL
Replace: USER_SHOW_USERNAME_EMAIL_DOES_NOT_EXIST
with: USER_SHOW_EMAIL_DOES_NOT_EXIST
& USER_SHOW_USERNAME_DOES_NOT_EXIST
With v0.9+:
Notice how SQLAlchemy allows us to keep using the old confirmed_at column name with the new
email_confirmed_at property.
See Advanced Porting topics for a workaround if you can not rename this property.
No known porting steps are needed for customized .html and .txt files.
7.27.7 Contact us
We believe this concludes the Basic Porting steps for for applications with minimal Flask-User customization.
If, after reading Porting Customizations and Advanced Porting topics, you still think this page is incomplete, please
email [email protected].
In v0.6, Flask-User was customized by adding parameters to the UserManager() instantiation. For example:
# Setup Flask-User
db_adapter = SQLAlchemyAdaper(db, User)
user_manager = UserManager(db_adapter, app,
register_form = CustomRegisterForm,
register_view_function = custom_register_view,
password_validator = custom_password_validator,
token_manager = CustomTokenManager())
In v0.9, Flask-User is customized by: - Extending the CustomUserManager class - Setting properties in its
customize() method - Overriding or extending methods
# Customize Flask-User
class CustomUserManager(UserManager):
# Override methods
def register_view(self):
...
# Extend methods
def password_validator(self):
super(CustomUserManager, self).password_validator()
...
In v0.9, almost all UserManager initiation parameters have been obsolted and now only accepts the following:
• Required parameters app, db and UserClass.
• Optional keyword parameters: UserEmailClass and UserInvitationClass.
See also:
UserManager Class
See Advanced Porting topics for a workaround if you can not merge the UserAuth and User classes.
Use the following approach to use the new class name while keeping the old table name:
class UserInvitation(db.Model):
__tablename__ = 'user_invite'
...
Please change:
user_manager.verify_password(password, user)
into:
verify_password(password, user.password)
The @confirm_email_required view decorator has been deprecated for security reasons.
In v0.6, the USER_ENABLE_LOGIN_WITHOUT_CONFIRM_EMAIL setting removed confirmed email protection for
all the views and required developers to re-protect the vulnerable views with @confirm_email_required.
In v0.9+ we adopt the opposite approach where the (renamed) USER_ALLOW_LOGIN_WITHOUT_CONFIRMED_EMAIL=True
setting continues to protect all the views, except those decorated with the new @allow_unconfirmed_email
decorator.
7.28.5 Contact us
We believe this concludes the Porting steps for for applications with a high degree of Flask-User customizations.
If, after reading Advanced Porting topics, you still think this page is incomplete, please email [email protected].
7.29.1 Flask-Login
We recommend NOT upgrading Flask-Login from v0.2.x to v0.3+ unless you need to.
Flask-Login changed user.is_authenticated, user.is_anonymous and user.is_active from being
methods in v0.2 to being properties in v0.3+.
This difference often requires changes in many places (in code and in template files):
The v0.6 TokenManager could only encrypt a single integer ID with less than 16 digits.
The v0.9+ TokenManager can now encrypt a list of items. Each item can be an integer or a string. Integers can be of
any size.
This change enables us to encrypt Mongo Object IDs as well as the last 8 bytes of a password, to invalidate tokens
after their password changed.
As a result, the generated tokens are different, which will affect these areas:
• v0.6 user-session tokens, that were stored in a browser cookie, are no longer valid in v0.9+ and the user will be
required to login again.
• Unused v0.6 password-reset tokens and user-invitation tokens, are no longer valid in v0.9+ and the affected
users will have to issue new forgot-password emails and new user invitatin emails. This effect is mitigated by
the fact that these tokens are meant to expire relatively quickly.
• user-session tokens and password-reset tokens become invalid if the user changes their password.
If you are unable to change property names, you can use Python’s getters and setters to form a bridge between required
property names and actual ones.
Here’s an example of how to map the v0.9 required email_confirmed_at property to your existing
confirmed_at property:
@email_confirmed_at.setter
def email_confirmed_at(self, value):
self.confirmed_at = value
Because the optional UserAuth and User have a one-to-one relationship to each other, you can use getters and
setters to have Flask-User manage two objects while specifying only the one User class:
# Relationship to user
user_id = db.Column(db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE'))
user = db.relationship('User', uselist=False)
# User information
active = db.Column('is_active', db.Boolean(), nullable=False, server_default='0')
first_name = db.Column(db.String(100), nullable=False, server_default='')
last_name = db.Column(db.String(100), nullable=False, server_default='')
# One-to-one Relationship
user_auth = db.relationship('UserAuth', uselist=False)
@username.setter
def username(self, value)
self.user_auth.username = value
@password.setter
def password(self, value)
self.user_auth.password = value
@email.setter
def email(self, value)
self.user_auth.email = value
@email_confirmed_at.setter
def email_confirmed_at(self, value)
self.user_auth.confirmed_at = value
# Setup Flask-User
user_manager = UserManager(app, db, User)
# -----------------------------------------------------------------
# This code snippet has not yet been tested. You can email
# [email protected] when it works or when you encounter problems.
# When enough people tested this I will remove this comment.
# Thank you!
@route(...)
@allow_unconfirmed_email
@login_required
def unprotected_view():
...
templates/base.html
All Flask-User forms extend from the template file tempates/base.h and Flask-User supplies a built-in version
that uses Bootstrap 3.
To make Flask-User use your page template, you will need to create a base.html template file in your application’s
templates directory.
Use {% block content %}{% endblock %} as a placeholder for the forms.
templates/flask_user/_public_base.html
Public forms are forms that do not require a logged-in user:
• templates/flask_user/forgot_password.html,
• templates/flask_user/login.html,
• templates/flask_user/login_or_register.html,
• templates/flask_user/register.html,
• templates/flask_user/request_email_confirmation.html, and
• templates/flask_user/reset_password.html.
Public forms extend the template file templates/flask_user/_public_base.html, which by default ex-
tends the template file templates/base.html.
If you want the public forms to use a base template file other than templates/base.html, create the
templates/flask_user/_public_base.html file in your application’s templates directory with the
following content:
{% extends 'my_public_base.html' %}
templates/flask_user/_authorized_base.html
Member forms are forms that require a logged-in user:
• templates/flask_user/change_password.html,
• templates/flask_user/change_username.html, and
• templates/flask_user/manage_emails.html.
Member forms extend the template file templates/flask_user/_authorized_base.html, which by de-
fault extends the template file templates/base.html.
If you want the member forms to use a base template file other than templates/base.html, create the
templates/flask_user/_authorized_base.html file in your application’s templates directory with
the following content:
{% extends 'my_authorized_base.html' %}
Summary
The following template files reside in the templates directory:
Flask Applications that want to be kept informed about certain actions that took place in the underlying Flask-User
extensions can do so by subscribing ‘signals’ to receive event notification.
Flask-User defines the following signals:
NB: Flask-User relies on Flask signals, which relies on the ‘blinker’ package. Event notification WILL NOT WORK
without first installing the ‘blinker’ package.
See http://pythonhosted.org/blinker/
AFTER BLINKER HAS BEEN INSTALLED, An application can receive event notifications by using the event sig-
nal’s connect_via() decorator:
@user_logged_in.connect_via(app)
def _after_login_hook(sender, user, **extra):
sender.logger.info('user logged in')
7.31.3 Troubleshooting
If the code looks right, but the tracking functions are not called, make sure to check to see if the ‘blinker’ package has
been installed (analyze the output of pip freeze).
7.32 Recipes
Some websites may prefer to show the login form and the register form on one page.
Flask-User (v0.4.9 and up) ships with a login_or_register.html form template which requires the following
application config settings:
• USER_LOGIN_TEMPLATE='flask_user/login_or_register.html'
• USER_REGISTER_TEMPLATE='flask_user/login_or_register.html'
This would accomplish the following:
• The /user/login and user/register URLs will now render login_or_register.html.
• login_or_register.html now displays a Login form and a Register form.
• The Login button will post to /user/login
• The Register button will post to /user/register
Some applications require code to execute just after a new user registered for a new account. This can be achieved by
subscribing to the user_registered signal as follows:
@user_registered.connect_via(app)
def _after_registration_hook(sender, user, **extra):
sender.logger.info('user registered')
If you want to populate your database with User records with hashed passwords use user_manager.
hash_password():
user = User(
email='[email protected]',
password=user_manager.hash_password('Password1'),
)
db.session.add(user)
db.session.commit()
Flask-User deliberately stayed away from implementing account tracking features because:
• What to track is often customer specific
• Where to store it is often customer specific
• Custom tracking is easy to implement using signals
Here’s an example of tracking login_count and last_login_ip:
@user_logged_in.connect_via(app)
def _track_logins(sender, user, **extra):
user.login_count += 1
user.last_login_ip = request.remote_addr
db.session.commit()
7.33 F.A.Q.
Flask-Security has been around since at least March 2012 and additionally offers Json/AJAX, MongoDB, Peewee, and
Basic HTTP Authentication.
Flask-User has been designed with Full customization in mind and additionally offers Username login and Interna-
tionalization. It exists since December 2013 and contains 661 statements with a 98% test coverage.
7.33. F.A.Q. 83
Flask-User Documentation, Release v1.0
Flask-User shields itself from database operations through a DBAdapter. It ships with a SQLAlchemyAdapter, but the
API is very simple, so other adapters can be easily added. See DbAdapter Interface.
• Template variables
• Template functions
• Signals
The following template variables are available for use in email and form templates:
The following template functions are available for use in email and form templates:
hash_password()
user_manager.hash_password(password)
# Returns hashed 'password' using the configured password hash
# Config settings: USER_PASSWORD_HASH_MODE = 'passlib'
# USER_PASSWORD_HASH = 'bcrypt'
# USER_PASSWORD_SALT = SECRET_KEY
verify_password()
user_manager.verify_password(password, user.password)
# Returns True if 'password' matches the user's 'hashed password'
# Returns False otherwise.
7.34.3 Signals
7.35 Misc
7.35.1 Status
7.35.2 Demo
The Flask-User Demo showcases Flask-User. To protect against spam mis-use, all email features have been disabled.
(If you’re the first visitor in the last hour, it may take a few seconds for Heroku to start this service)
7.35. Misc 85
Flask-User Documentation, Release v1.0
7.35.6 Acknowledgements
This project would not be possible without the use of the following amazing offerings:
• Flask
• Flask-BabelEx and Flask-Babel
• Flask-Login
• Flask-Mail
• SQLAlchemy and Flask-SQLAlchemy
• WTForms and Flask-WTF
7.35.7 Contributors
7.36 Customize
Flask-User has been designed with full customization in mind, and and here is a list of behaviors that can be customized
as needed:
• Emails
• Registration Form
• Labels and Messages
• Form Templates
• View functions
• Password and Username validators
• Password hashing
• Token generation
The following can be customized by editing the English Babel translation file:
• Flash messages (one-time system messages)
• Form field labels
• Validation messages
See Internationalization
We recommend asking for as little information as possible during user registration, and to only prompt new users for
additional information after the registration process has been completed.
Some Websites, however, do want to ask for additional information in the registration form itself.
Flask-User (v0.4.5 and up) has the capability to store extra registration fields in the User or the UserProfile records.
Extra registration fields in the User data-model
Extra fields must be defined in the User data-model:
def is_active(self):
return self.is_enabled
A custom RegisterForm must be defined with field names exactly matching the names of the data-model fields:
class MyRegisterForm(RegisterForm):
first_name = StringField('First name', validators=[DataRequired('First name is
˓→required')])
A custom templates/flask_user/register.html file must be copied and defined with the extra fields. See
Form Templates.
When a new user submits the Register form, Flask-User examines the field names of the form and the User data-model.
For each matching field name, the form field value will be stored in the corresponding User field.
See Github repository; example_apps/register_form_app
Extra registration fields in UserProfile data-model
• Add extra fields to the User data-model
7.36. Customize 87
Flask-User Documentation, Release v1.0
Forms are generated using Flask Jinja2 template files. Flask will first look for template files in the application’s
templates directory before looking in Flask-User’s templates directory.
Forms can thus be customized by copying the built-in Form template files from the Flask-User directory to your
application’s directory and editing the new copy.
Flask-User typically installs in the flask_user sub-directory of the Python packages directory. The location of this
directory depends on Python, virtualenv and pip and can be determined with the following command:
python -c "from distutils.sysconfig import get_python_lib; print get_python_lib();"
If you’d like the Login form and the Register form to appear on one page, you can use the following application config
settings:
# Place the Login form and the Register form on one page:
# Only works for Flask-User v0.4.9 and up
USER_LOGIN_TEMPLATE = 'flask_user/login_or_register.html'
USER_REGISTER_TEMPLATE = 'flask_user/login_or_register.html'
Flask-User comes standard with a password validator (at least 6 chars, 1 upper case let-
ter, 1 lower case letter, 1 digit) and with a username validator (at least 3 characters in
“abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._”).
Custom validators can be specified by setting an property on the Flask-User’s UserManager object:
user_manager = UserManager(db_adapter,
password_validator=my_password_validator,
username_validator=my_username_validator)
user_manager.init_app(app)
USER_PASSWORD_HASH = 'sha512_crypt'
7.36. Customize 89
Flask-User Documentation, Release v1.0
my_password_crypt_context = CryptContext(
schemes=['bcrypt', 'sha512_crypt', 'pbkdf2_sha512'])
user_manager = UserManager(db_adapter, app,
password_crypt_context=my_password_crypt_context)
By sub-classing hash_password():
class MyUserManager(UserManager):
def hash_password(self, password):
return self.password
The built-in View Functions contain considerable business logic, so we recommend first trying the approach of Form
Templates before making use of customized View Functions.
Custom view functions are specified by setting an property on the Flask-User’s UserManager object:
# View functions
user_manager = UserManager(db_adapter,
change_password_view_function = my_view_function1,
change_username_view_function = my_view_function2,
confirm_email_view_function = my_view_function3,
email_action_view_function = my_view_function4,
forgot_password_view_function = my_view_function5,
login_view_function = my_view_function6,
logout_view_function = my_view_function7,
manage_emails_view_function = my_view_function8,
register_view_function = my_view_function9,
resend_email_confirmation_view_function = my_view_function10,
reset_password_view_function = my_view_function11,
)
user_manager.init_app(app)
To be documented.
7.36.8 Emails
Emails are generated using Flask Jinja2 template files. Flask will first look for template files in the application’s
templates directory before looking in Flask-User’s templates directory.
Emails can thus be customized by copying the built-in Email template files from the Flask-User directory to your
application’s directory and editing the new copy.
Flask-User typically installs in the flask_user sub-directory of the Python packages directory. The location of this
directory depends on Python, virtualenv and pip and can be determined with the following command:
cd ~/path/to/YOURAPP/YOURAPP
mkdir -p templates/flask_user/emails
cp ~/.virtualenvs/ENVNAME/lib/python2.7/site-packages/flask_user/templates/flask_user/
˓→emails/* templates/flask_user/emails/.
Each email type has three email template files. The ‘registered’ email for example has the following files:
templates/flask_user/emails/base_subject.txt
templates/flask_user/emails/base_message.html
templates/flask_user/emails/base_message.txt
The base template files are used to define email elements that are similar in all types of email messages.
7.36. Customize 91
Flask-User Documentation, Release v1.0
<p>Sincerely,<br/>
The Flask-User Team</p>
</div>
{% extends "flask_user/emails/base_message.html" %}
{% block message %}
<p>Thank you for registering with Flask-User.</p>
<p>Visit the link below to complete your registration:</p>
<p><a href="{{ confirm_email_link }}">Confirm your email address</a>.</p>
<p>If you did not initiate this registration, you may safely ignore this email.</p>
{% endblock %}
7.36.9 SQLDbAdapter
Flask-User uses SQLDbAdapter and installs Flask-SQLAlchemy by default. No customization is required to work
with SQL databases.
Configure the SQLALCHEMY_DATABASE_URI setting in your app config to point to the desired server and database.
7.36.10 MongoDbAdapter
# Setup Flask-MongoEngine
from Flask-MongoEngine import MongoEngine
db = MongoEngine(app)
# Customize Flask-User
class CustomUserManager(UserManager):
# User information
first_name = db.StringField(default='')
last_name = db.StringField(default='')
# Relationships
roles = db.ListField(db.StringField(), default=[])
# Setup Flask-User
user_manager = CustomUserManager(app, db, User)
Configure the MONGODB_SETTINGS setting in your app config to point to the desired server and database.
7.36.11 SMTPEmailAdapter
Flask-User uses the SMTPEmailAdapter and install Flask-Mail by default. No customization is required to use SMT-
PEmailAdapter to send emails via SMTP.
Configure the MAIL_... settings in your app config to point to the desired SMTP server and account.
7.36.12 SendmailEmailAdapter
and minor customization is required use to SendmailEmailAdapter to send emails via sendmail.:
# Customize Flask-User
class CustomUserManager(UserManager):
# Setup Flask-User
user_manager = CustomUserManager(app, db, User)
7.36.13 SendgridEmailAdapter
and minor customization is required to use SendgridEmailAdapter to send emais via SendGrid:
7.36. Customize 93
Flask-User Documentation, Release v1.0
# Customize Flask-User
class CustomUserManager(UserManager):
# Setup Flask-User
user_manager = CustomUserManager(app, db, User)
Configuration: TBD.
95
Flask-User Documentation, Release v1.0
96 Index
Flask-User Documentation, Release v1.0
Index 97
Flask-User Documentation, Release v1.0
V
verify_password() (PasswordManager method), 32
verify_password() (UserManager__Utils method), 58
verify_token() (TokenManager method), 33
verify_token() (UserManager__Utils method), 58
98 Index