Flask user session management.

Overview

Flask-Login

Tests coverage Software License

Flask-Login provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering your users' sessions over extended periods of time.

Flask-Login is not bound to any particular database system or permissions model. The only requirement is that your user objects implement a few methods, and that you provide a callback to the extension capable of loading users from their ID.

Installation

Install the extension with pip:

$ pip install flask-login

Usage

Once installed, the Flask-Login is easy to use. Let's walk through setting up a basic application. Also please note that this is a very basic guide: we will be taking shortcuts here that you should never take in a real application.

To begin we'll set up a Flask app:

import flask

app = flask.Flask(__name__)
app.secret_key = 'super secret string'  # Change this!

Flask-Login works via a login manager. To kick things off, we'll set up the login manager by instantiating it and telling it about our Flask app:

import flask_login

login_manager = flask_login.LoginManager()

login_manager.init_app(app)

To keep things simple we're going to use a dictionary to represent a database of users. In a real application, this would be an actual persistence layer. However it's important to point out this is a feature of Flask-Login: it doesn't care how your data is stored so long as you tell it how to retrieve it!

# Our mock database.
users = {'[email protected]': {'password': 'secret'}}

We also need to tell Flask-Login how to load a user from a Flask request and from its session. To do this we need to define our user object, a user_loader callback, and a request_loader callback.

class User(flask_login.UserMixin):
    pass


@login_manager.user_loader
def user_loader(email):
    if email not in users:
        return

    user = User()
    user.id = email
    return user


@login_manager.request_loader
def request_loader(request):
    email = request.form.get('email')
    if email not in users:
        return

    user = User()
    user.id = email

    # DO NOT ever store passwords in plaintext and always compare password
    # hashes using constant-time comparison!
    user.is_authenticated = request.form['password'] == users[email]['password']

    return user

Now we're ready to define our views. We can start with a login view, which will populate the session with authentication bits. After that we can define a view that requires authentication.

@app.route('/login', methods=['GET', 'POST'])
def login():
    if flask.request.method == 'GET':
        return '''
               <form action='login' method='POST'>
                <input type='text' name='email' id='email' placeholder='email'/>
                <input type='password' name='password' id='password' placeholder='password'/>
                <input type='submit' name='submit'/>
               </form>
               '''

    email = flask.request.form['email']
    if flask.request.form['password'] == users[email]['password']:
        user = User()
        user.id = email
        flask_login.login_user(user)
        return flask.redirect(flask.url_for('protected'))

    return 'Bad login'


@app.route('/protected')
@flask_login.login_required
def protected():
    return 'Logged in as: ' + flask_login.current_user.id

Finally we can define a view to clear the session and log users out:

@app.route('/logout')
def logout():
    flask_login.logout_user()
    return 'Logged out'

We now have a basic working application that makes use of session-based authentication. To round things off, we should provide a callback for login failures:

@login_manager.unauthorized_handler
def unauthorized_handler():
    return 'Unauthorized'

Complete documentation for Flask-Login is available on ReadTheDocs.

Contributing

We welcome contributions! If you would like to hack on Flask-Login, please follow these steps:

  1. Fork this repository
  2. Make your changes
  3. Install the requirements in dev-requirements.txt
  4. Submit a pull request after running make check (ensure it does not error!)

Please give us adequate time to review your submission. Thanks!

Comments
  • current_user instance is of LocalProxy type

    current_user instance is of LocalProxy type

    Hi, when using current_user instance I was having a weird bug with MongoEngine, then I decided to debug and when checking:

    ipdb> type(current_user)
    <class 'werkzeug.local.LocalProxy'>
    

    That's not desired if I will use it directly. MongoEngine complains when using that instance during query/update, etc... Is there any way to unwrap the proxy? Right now I have to query to the DB to get the real object.

    Thanks

    opened by eka 35
  • Broken compatibility with Werkzeug 0.9 and Flask 0.10

    Broken compatibility with Werkzeug 0.9 and Flask 0.10

    The current release version does not work well with Flask 0.10 and the current code in Flask-Login in master does not work with Werkzeug 0.9.

    The two changes that break it:

    • sessions in flask can no longer contain binary data
    • headers are now unicode.
    Bug 
    opened by mitsuhiko 20
  • Drop Python 2.7 support

    Drop Python 2.7 support

    Fixes #508.

    This removes all support for and references to Python 2.7, including in the test matrix. Most changes were performed through running 2to3 but some work was performed manually, such as imports and removing the _compat module. Running make clean reports all is well.

    opened by le717 19
  • Backwards compatible imports (_create_identifier)

    Backwards compatible imports (_create_identifier)

    Can we keep the global import namespace compatible with 0.3.x version for utils introduced in 088ac3cf5e0597d59224fcfb0536bea031a9ae17 ?

    __init__.py

    
    from utils import _create_identifier, ...
    
    __all__ = ('_create_identifier', ...)
    

    Thanks!

    -- Make sure these boxes are checked before submitting your issue--thank you!

    • [x] Ensure you are using the latest PyPI release.
    • [x] Read the CHANGES document thoroughly.
    • [x] Provide a clear and simple set of steps to reproduce your issue for others.
    opened by jirikuncar 19
  • Fix handling of X-Forwarded-For header

    Fix handling of X-Forwarded-For header

    The code that calculates a user's identifier uses the remote address or the contents of the X-Forwarded-For header doesn't account for the fact that the X-Forwarded-For header can contain a comma separated list of remote addresses, which is the case for scenarios in which 2+ proxy servers are involved in the request forwarding. This caveat causes Flask-Login to unexpectedly log users out when the combination of proxy servers that routed a previous request change.

    See http://tools.ietf.org/html/rfc7239 for more information about X-Forwarded-For standard.

    opened by sholsapp 19
  • Avoid touching the session unless something changed

    Avoid touching the session unless something changed

    Some session backends will try to detect changes made to the session dictionary and only save if the session was modified. The pop() call will set modified = True in such a backend. By checking if the "remember" key exists before we pop it we avoid this behaviour.

    opened by insmo 15
  • Bump jinja2 from 2.10.3 to 2.11.3 in /requirements

    Bump jinja2 from 2.10.3 to 2.11.3 in /requirements

    Bumps jinja2 from 2.10.3 to 2.11.3.

    Release notes

    Sourced from jinja2's releases.

    2.11.3

    This contains a fix for a speed issue with the urlize filter. urlize is likely to be called on untrusted user input. For certain inputs some of the regular expressions used to parse the text could take a very long time due to backtracking. As part of the fix, the email matching became slightly stricter. The various speedups apply to urlize in general, not just the specific input cases.

    2.11.2

    2.11.1

    This fixes an issue in async environment when indexing the result of an attribute lookup, like {{ data.items[1:] }}.

    2.11.0

    This is the last version to support Python 2.7 and 3.5. The next version will be Jinja 3.0 and will support Python 3.6 and newer.

    Changelog

    Sourced from jinja2's changelog.

    Version 2.11.3

    Released 2021-01-31

    • Improve the speed of the urlize filter by reducing regex backtracking. Email matching requires a word character at the start of the domain part, and only word characters in the TLD. :pr:1343

    Version 2.11.2

    Released 2020-04-13

    • Fix a bug that caused callable objects with __getattr__, like :class:~unittest.mock.Mock to be treated as a :func:contextfunction. :issue:1145
    • Update wordcount filter to trigger :class:Undefined methods by wrapping the input in :func:soft_str. :pr:1160
    • Fix a hang when displaying tracebacks on Python 32-bit. :issue:1162
    • Showing an undefined error for an object that raises AttributeError on access doesn't cause a recursion error. :issue:1177
    • Revert changes to :class:~loaders.PackageLoader from 2.10 which removed the dependency on setuptools and pkg_resources, and added limited support for namespace packages. The changes caused issues when using Pytest. Due to the difficulty in supporting Python 2 and :pep:451 simultaneously, the changes are reverted until 3.0. :pr:1182
    • Fix line numbers in error messages when newlines are stripped. :pr:1178
    • The special namespace() assignment object in templates works in async environments. :issue:1180
    • Fix whitespace being removed before tags in the middle of lines when lstrip_blocks is enabled. :issue:1138
    • :class:~nativetypes.NativeEnvironment doesn't evaluate intermediate strings during rendering. This prevents early evaluation which could change the value of an expression. :issue:1186

    Version 2.11.1

    Released 2020-01-30

    • Fix a bug that prevented looking up a key after an attribute ({{ data.items[1:] }}) in an async template. :issue:1141

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the Security Alerts page.
    dependencies python 
    opened by dependabot[bot] 13
  • Exception: No user_loader has been installed for this LoginManager

    Exception: No user_loader has been installed for this LoginManager

    For apps with multiple User models, is there any way to alter the user_loader / load_user() to be able to distinguish between the models? The standard is

    @login_manager.user_loader
    def load_user(user_id):
        return User.get(user_id)
    

    I need to somehow discern which model the user_id passed belongs to and insert a condition to replace User.get() with the appropriate model.

    Bug 
    opened by NikolaJankovic 13
  • Flask WTF and session_protection = 'strong'

    Flask WTF and session_protection = 'strong'

    This https://github.com/maxcountryman/flask-login/commit/9c8f3ca7441fa0abb506093c7161b5aa4cad88df has created me a lot of problems using forms with csrf token enabled and session protection set to strong this is the issue that I was getting as well https://github.com/lepture/flask-wtf/issues/197 and unsetting the session_protection made it work.

    I can't figure out how I can make it work again using 'strong', could you please provide me some useful links or examples?

    opened by shipperizer 13
  • Support force-logout for active sessions

    Support force-logout for active sessions

    Right now you can only force-logout a remember-me token by using a custom token. It would be nice if there was a clean way to do this for active sessions, too.

    From a quick look at the code this could probably be done by making get_id return e.g. a tuple of userid, token and the user_loader handling this token accordingly (retrieving the user from the DB and checking if the tokens match). However, the documentation is quite clear about the user id having to be unicode and a second look at the code shows that the user id actually converted to a string at some point: data = encode_cookie(str(session['user_id'])) (actually, shouldn't this be unicode and not str?).

    Sure, I could use a custom string representation such as id:token but it feels dirty.

    Contributor Friendly Feature Request 
    opened by ThiefMaster 13
  • Re-enable localisation of flash messages after migration to Flask 0.10+

    Re-enable localisation of flash messages after migration to Flask 0.10+

    Flask 0.10+ makes it impossible to use login_manager.login_message = lazy_gettext('Please log in') (no more pickle), thus buggering localisation of flask-login's flash messages.

    Add a localize_callback attribute to LoginManager that, if present, will be called with login_message and needs_refresh_message and whose return value will be sent flash.

    opened by deanishe 13
  • deprecate `__about__` module

    deprecate `__about__` module

    The only thing that might be relevant to runtime inspection is __version__, which is already exported. The rest is package metadata that should be in setup.cfg, which can be inspected with importlib.metadata if needed.

    opened by davidism 0
  • don't look at the `X-Forwarded-For` header

    don't look at the `X-Forwarded-For` header

    Flask-Login has no way to guarantee that this header is correct because it doesn't know how many proxies the app is or isn't deployed behind. Instead, it should always read request.remote_addr, and assume that the user has configured ProxyFix if necessary.

    opened by davidism 1
  • adjust how session protection attribute and config interact

    adjust how session protection attribute and config interact

    Currently, login_manager.session_protection is only considered if app.config does not have the SESSION_PROTECTION key. Session protection is the only config that works this way, and this is not a standard pattern for Flask config. A more common pattern would be to use the attribute if the config is set to some default value, but that doesn't work in this case because None has meaning (probably should be False instead).

    As part of #696, I also wanted to set all available config to default values in init_app rather than using config.get with defaults spread out across the code. However, this doesn't work for session protection.

    At minimum, I think init_app should do app.config.setdefault("SESSION_PROTECTION", self.session_protection). Requiring the extension to be configured before registering it on the app is a standard pattern in Flask, as you can't guarantee in general that config changed afterwards will take effect anyway.

    An extra step would be to deprecate then remove the attribute and only use the config. I think this makes sense because session protection is very dependent on how the app is deployed, which is what app.config is for.

    opened by davidism 1
  • remove anonymous user

    remove anonymous user

    This is a constant source of confusion for users. They don't understand why is_authenticated is always true for UserMixin even if it's not the logged in user. They get tripped up when they try to access attributes on current_user that aren't available on AnonymousUserMixin.

    Whenever I'm writing my own quick login implementation, I set g.user to None if there's no logged in user, and the current_user proxy would be unbound (if current_user would look False).

    You can return any object you want from user_loader. If an application needs an anonymous user system, they can return an anonymous user object from user_loader. They'll most likely need that anyway as even anonymous users might take actions that need to be associated together, and a single anonymous user wouldn't work for that.

    I think removing this might also make it more obvious that you can return more than one type from user_loader, like AdminUser and RegularUser for example.

    I realize this is a larger departure from current behavior than other refactors we've been doing. But I think it's worth doing for a simpler API.

    opened by davidism 3
  • remove `LOGIN_DISABLED` config

    remove `LOGIN_DISABLED` config

    It should not be possible to disable login. Especially not as a config, it doesn't make sense to configure this per-deployment. I'm not sure how it would even be used in testing, since any function protected by login would presumably also be using current_user and break when that isn't set. We also have LoginTestClient to make a given user logged in for test requests.

    opened by davidism 0
  • config keys should be prefixed

    config keys should be prefixed

    Extensions should namespace any values they use in app.config and g with their name (without the "Flask-" prefix). It's usually a good idea to set the default config in init_app as well and access them with []. This makes it easier to reason about what extension manages what config.

    Flask-Login currently uses the following keys:

    • USE_SESSION_FOR_NEXT, default False
    • REMEMBER_COOKIE_NAME, default "remember_token"
    • REMEMBER_COOKIE_DOMAIN, default None
    • REMEMBER_COOKIE_PATH, default "/"
    • REMEMBER_COOKIE_SECURE, default False
    • REMEMBER_COOKIE_HTTPONLY, default True
    • REMEMBER_COOKIE_SAMESITE, default None
    • REMEMBER_COOKIE_DURATION, default timedelta(days=365), converts int
    • REMEMBER_COOKIE_REFRESH_EACH_REQUEST, default None, should probably be False
    • AUTH_HEADER_NAME, default "Authorization", removed in 0.7 along with header_loader
    • SESSION_PROTECTION, default self.session_protection, default "basic"
    • FORCE_HOST_FOR_REDIRECTS, default None
    • LOGIN_DISABLED, default False
    opened by davidism 1
Releases(0.6.2)
  • 0.6.2(Jul 26, 2022)

  • 0.6.1(May 2, 2022)

  • 0.6.0(Mar 30, 2022)

    • Changes: https://github.com/maxcountryman/flask-login/blob/main/CHANGES.md#version-060

    This release sets new minimum versions of Python, Flask, and Werkzeug, and fixes compatibility with the latest versions of those.

    • Python >= 3.7
    • Flask >= 1.0.4, this will be bumped to reflect the latest supported release (2.1) in the future
    • Werkzeug >= 1.0.1, this will be bumped to reflect the latest supported release (2.1) in the future
    Source code(tar.gz)
    Source code(zip)
Owner
Max Countryman
Distributed systems, functional programming, cloud computing.
Max Countryman
Customizable User Authorization & User Management: Register, Confirm, Login, Change username/password, Forgot password and more.

Flask-User v1.0 Attention: Flask-User v1.0 is a Production/Stable version. The previous version is Flask-User v0.6. User Authentication and Management

Ling Thio 988 Sep 8, 2022
Customizable User Authorization & User Management: Register, Confirm, Login, Change username/password, Forgot password and more.

Flask-User v1.0 Attention: Flask-User v1.0 is a Production/Stable version. The previous version is Flask-User v0.6. User Authentication and Management

Ling Thio 916 Feb 15, 2021
User Authentication in Flask using Flask-Login

User-Authentication-in-Flask Set up & Installation. 1 .Clone/Fork the git repo and create an environment Windows git clone https://github.com/Dev-Elie

ONDIEK ELIJAH OCHIENG 22 Aug 20, 2022
This script helps you log in to your LMS account and enter the currently running session

This script helps you log in to your LMS account and enter the currently running session, all in a second

Ali Ebrahimi 5 Sep 1, 2022
This program automatically logs you into a Zoom session at your alloted time

This program automatically logs you into a Zoom session at your alloted time. Optionally you can choose to have end the session at your allotted time.

null 9 Sep 19, 2022
Flask JWT Router is a Python library that adds authorised routes to a Flask app.

Read the docs: Flask-JWT-Router Flask JWT Router Flask JWT Router is a Python library that adds authorised routes to a Flask app. Both basic & Google'

Joe Gasewicz 51 Aug 19, 2022
Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.

Welcome to django-allauth! Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (soc

Raymond Penners 7.4k Sep 15, 2022
Ready-to-use and customizable users management for FastAPI

FastAPI Users Ready-to-use and customizable users management for FastAPI Documentation: https://frankie567.github.io/fastapi-users/ Source Code: https

Fran├žois Voron 2.2k Sep 18, 2022
Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.

Welcome to django-allauth! Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (soc

Raymond Penners 7.5k Sep 27, 2022
An open source Flask extension that provides JWT support (with batteries included)!

Flask-JWT-Extended Features Flask-JWT-Extended not only adds support for using JSON Web Tokens (JWT) to Flask for protecting views, but also many help

Landon Gilbert-Bland 1.4k Sep 18, 2022
Simple extension that provides Basic, Digest and Token HTTP authentication for Flask routes

Flask-HTTPAuth Simple extension that provides Basic and Digest HTTP authentication for Flask routes. Installation The easiest way to install this is t

Miguel Grinberg 1.1k Sep 14, 2022
Doing the OAuth dance with style using Flask, requests, and oauthlib.

Flask-Dance Doing the OAuth dance with style using Flask, requests, and oauthlib. Currently, only OAuth consumers are supported, but this project coul

David Baumgold 900 Sep 18, 2022
Strong, Simple, and Precise security for Flask APIs (using jwt)

flask-praetorian Strong, Simple, and Precise security for Flask APIs API security should be strong, simple, and precise like a Roman Legionary. This p

Tucker Beck 316 Sep 25, 2022
FastAPI-Login tries to provide similar functionality as Flask-Login does.

FastAPI-Login FastAPI-Login tries to provide similar functionality as Flask-Login does. Installation $ pip install fastapi-login Usage To begin we hav

null 369 Sep 23, 2022
Simple Login - Login Extension for Flask - maintainer @cuducos

Login Extension for Flask The simplest way to add login to flask! Top Contributors Add yourself, send a PR! How it works First install it from PyPI. p

Flask Extensions 173 Sep 13, 2022
Quick and simple security for Flask applications

Note This project is non maintained anymore. Consider the Flask-Security-Too project as an alternative. Flask-Security It quickly adds security featur

Matt Wright 1.6k Sep 18, 2022
A flask extension for managing permissions and scopes

Flask-Pundit A simple flask extension to organize resource authorization and scoping. This extension is heavily inspired by the ruby Pundit library. I

Anurag Chaudhury 47 Sep 14, 2022
Quick and simple security for Flask applications

Note This project is non maintained anymore. Consider the Flask-Security-Too project as an alternative. Flask-Security It quickly adds security featur

Matt Wright 1.6k Feb 17, 2021
Simple extension that provides Basic, Digest and Token HTTP authentication for Flask routes

Flask-HTTPAuth Simple extension that provides Basic and Digest HTTP authentication for Flask routes. Installation The easiest way to install this is t

Miguel Grinberg 940 Feb 13, 2021