Flask-Security Documentation

repository·main·Indexed 20 days ago

https://github.com/pallets-eco/flask-security

A comprehensive security extension for Flask that provides authentication and authorization features following OWASP best practices. It includes tools for user and role management via datastores, view protection decorators, password validation, and a wide array of signals for hooking into security events like registration and two-factor authentication.

Tokens
42.9K
Snippets
82
Records
155
Agent score
72%

What's inside Flask-Security

  1. Overview of Flask-Security

    main

    Flask-Security is a library designed to quickly add security features to Flask applications. It aims to follow OWASP best practices and provides a 'batteries-included' experience by bundling support for common authentication and authorization use cases. Key features include:

    • Multi-Factor Authentication: Support for SMS, email, and authenticator apps.
    • Modern Auth Standards: WebAuthn/Passkey support, Refresh Tokens, and OAuth (via authlib).
    • Identity Management: Username recovery, changing usernames, changing emails, and email normalization/validation.
    • Unified Sign-in: Support for username, phone, and passwordless authentication.
    • Security Decorators: A freshness decorator to ensure sensitive operations require recent authentication.
  2. Overview of Flask-Security features

    main

    Flask-Security is an extension designed to quickly add common security mechanisms to Flask applications. It provides a comprehensive suite of features including:

    • Authentication: Supports session-based, Basic HTTP, or token-based authentication.
    • User Management: Includes optional user registration, account activation (via email), username management (recovery, change, configuration), and email change capabilities.
    • Access Control: Role and Permission management.
    • Password & Account Security: Password recovery and resetting, and login tracking.
    • Multi-Factor Authentication: Two-factor authentication (2FA) via email, SMS, or authenticator apps, as well as Passkey (Webauthn) support.
    • Social Login: OAuth support for providers like Google and GitHub.
    • Modern Web Support: Built-in JSON/Ajax support and Single Page Application (SPA) patterns.
  3. How session-based authentication works in Flask-Security

    main

    Flask-Security uses Flask-Login to handle session-based authentication. It automatically configures Flask-Login using its own settings and utilizes the alternative token feature to associate the fs_uniquifier value with the user. This allows you to invalidate all existing sessions for a specific user by changing their fs_uniquifier without changing their user ID.

    Flask-WTF integrates with the session to provide CSRF support. Flask-Security extends this to ensure CSRF is required for requests authenticated via session cookies, but not for those authenticated via tokens.

  4. Customize authentication and authorization error handling

    main

    Flask-Security allows you to override how the application responds to failed authentication (unauthenticated) and failed authorization (unauthorized) via three main methods:

    1. Security.render_json: Controls the JSON response format for both 401 and 403 errors.
    2. Security.unauthn_handler: Overrides the default behavior when authentication fails (e.g., @login_required or @auth_required).
    3. Security.unauthz_handler: Overrides the default behavior when authorization fails (e.g., @roles_required or @permissions_required).

    Default Behavior Summary

    Authentication Failures (401)

    • JSON Request: If the request content-type is application/json or the Accept header prefers application/json, render_json is called with a 401 status code.
    • Non-JSON Request: The SECURITY_MSG_UNAUTHENTICATED message is flashed and the user is redirected to the login view.
    • HTTP Basic Auth: If @http_auth_required or @auth_required("basic") is used, a 401 is returned with the WWW-Authenticate header set to Basic realm="xxxx", where the realm is defined by SECURITY_DEFAULT_HTTP_AUTH_REALM.

    Authorization Failures (403)

    • JSON Request: render_json is called with a 403 status code.
    • Non-JSON Request: If SECURITY_UNAUTHORIZED_VIEW is defined, the user is redirected there. Otherwise, abort(403) is called.
  5. Understand the fs_uniquifier and Session Invalidation

    main

    The fs_uniquifier is a critical attribute used to manage session and token validity.

    • Session Invalidation: Changing a user's password or updating their fs_uniquifier immediately invalidates all existing sessions.
    • Token Invalidation: By default, changing the password also invalidates all authentication tokens because they rely on fs_uniquifier.
    • Decoupling Tokens from Passwords: If you want password changes to not invalidate authentication tokens, ensure your UserModel contains an attribute named fs_token_uniquifier. Flask-Security will use that for tokens instead of the standard fs_uniquifier.
  6. Supported database backends for Flask-Security

    main

    Flask-Security integrates with several common database libraries for data persistence. It supports the following Flask extensions out of the box:

    • Flask-SQLAlchemy
    • MongoEngine
    • Peewee Flask utils
    • SQLAlchemy sessions
    • Flask-SQLAlchemy-Lite
  7. Configure redirect destinations and 'next' parameter behavior

    main

    Flask-Security uses redirects frequently, especially when working with forms. Most redirect destinations are configurable via settings, but the next query parameter takes precedence.

    The 'next' Parameter

    Flask-Security attempts to propagate the next query parameter through the authentication lifecycle (e.g., from login to two-factor verification).

    When a redirect is triggered, the system determines the destination in this order of priority:

    1. The next value in request.args (query string).
    2. The next value in request.form (POST data).
    3. The value defined in SECURITY_POST_LOGIN_VIEW.

    Example Lifecycle

    If an unauthenticated user accesses /protected:

    1. Initial Redirect: The unauthenticated handler redirects to /login?next=/protected.
    2. Login Submission: The login form action includes the next param, resulting in a POST to /login?next=/protected.
    3. 2FA Step: If 2FA is required, the system redirects to /tf-verify?next=/protected.
    4. Final Redirect: After successful 2FA validation, the system finds next=/protected in the request arguments and redirects the user to the original destination.
  8. How CSRF token checking works in Flask-Security

    main

    CSRF tokens are checked in one of three ways, depending on your configuration, in this specific order:

    1. Global @before_request handler: If flask_wtf.CSRFProtect(app) is called, it sets up a handler that checks all requests. On error, it returns an HTTP 400 with a small HTML snippet. You can disable this global check by setting app.config["WTF_CSRF_CHECK_DEFAULT"] = False.
    2. Flask-Security decorators: Using decorators like @unauth_csrf or @auth_required. On error, it returns a JSON response or raises a CSRFError (resulting in an HTTP 400).
    3. Form validation: For any form derived from FlaskForm. The error is recorded in the csrf_token field, and the view decides how to respond.
  9. Configure WebAuthn/Passkeys (Beta)

    main

    Flask-Security supports WebAuthn (standardized protocol for authenticators like YubiKey or mobile biometrics) as either a 'first' or 'secondary' authentication factor. This feature is currently in Beta.

    To use this, you must configure the WebAuthn settings in your application configuration.

  10. Use User and Role Mixins for models

    main

    To integrate your application models with Flask-Security, your models should inherit from the provided Mixin classes:

    • UserMixin: Provides standard user identity and authentication helpers.
    • RoleMixin: Provides standard role-based authorization helpers.
    • WebAuthnMixin: Adds support for WebAuthn authentication.
    • RefreshTrackerMixin: Adds support for tracking refresh tokens.
  11. How the Two-Factor (2FA) API works

    main

    The 2FA API provides four primary flows. When using JSON, the application must explicitly call these endpoints:

    1. Normal Login: After a successful /login or /us-signin (providing identity and password), if 2FA is required, the client must POST to /tf-validate with the correct code.
    2. Changing 2FA Setup:
      • GET /tf-setup: Returns available methods and current configuration.
      • POST /tf-setup: Sets a new primary method. Returns a state_token for SMS/Email or a QR code for Authenticator apps.
      • POST /tf-setup/<state_token>: Validates the code to permanently store the new configuration.
    3. Initial Login/Registration: A user who hasn't set up 2FA yet must POST to /tf-setup to choose a method, then POST to /tf-validate to complete the process.
    4. Rescue: Users who lost their device can use /tf-rescue to access recovery options like email-based one-time codes or previously generated recovery codes.
  12. Manage Authentication Tokens and Refresh Tokens

    main

    Flask-Security supports simple authentication tokens and a robust refresh token system.

    Authentication Tokens

    Tokens are tied to a uniquifier field in the UserModel.

    • Default field: fs_uniquifier. Changing this (e.g., via UserDatastore.set_uniquifier) invalidates all existing tokens. This happens automatically on password changes.
    • Isolating password changes: To prevent password changes from invalidating tokens, add an fs_token_uniquifier field to your UserModel (must be unique=True). Use UserDatastore.set_token_uniquifier to update it.
    • Expiry: Controlled by SECURITY_TOKEN_MAX_AGE (global) or via a callable set in SECURITY_TOKEN_EXPIRE_TIMESTAMP (per-token).

    Refresh Tokens

    When enabled, the refresh token feature provides:

    • Rotation & Protection: Each time a new token is requested via the .refresh_token endpoint, a new refresh token is generated, making them single-use.
    • Storage: Uses an FsRefreshTracker DB model to track token families.
    • Delivery: Returned via a cookie (default, http-only) or in the JSON response.
    • Revocation: Best practice is to pass the refresh_token to the .logout endpoint to revoke the token and its tracker.