API
***

The external (json/form) API is described here


Core
====

class flask_security.Security(app=None, datastore=None, register_blueprint=True, login_form=<class 'flask_security.forms.LoginForm'>, verify_form=<class 'flask_security.forms.VerifyForm'>, confirm_register_form=<class 'flask_security.forms.ConfirmRegisterForm'>, register_form=<class 'flask_security.forms.RegisterForm'>, forgot_password_form=<class 'flask_security.forms.ForgotPasswordForm'>, reset_password_form=<class 'flask_security.forms.ResetPasswordForm'>, change_password_form=<class 'flask_security.forms.ChangePasswordForm'>, send_confirmation_form=<class 'flask_security.forms.SendConfirmationForm'>, passwordless_login_form=<class 'flask_security.forms.PasswordlessLoginForm'>, two_factor_verify_code_form=<class 'flask_security.forms.TwoFactorVerifyCodeForm'>, two_factor_setup_form=<class 'flask_security.forms.TwoFactorSetupForm'>, two_factor_rescue_form=<class 'flask_security.forms.TwoFactorRescueForm'>, two_factor_select_form=<class 'flask_security.tf_plugin.TwoFactorSelectForm'>, mf_recovery_codes_form=<class 'flask_security.recovery_codes.MfRecoveryCodesForm'>, mf_recovery_form=<class 'flask_security.recovery_codes.MfRecoveryForm'>, us_signin_form=<class 'flask_security.unified_signin.UnifiedSigninForm'>, us_setup_form=<class 'flask_security.unified_signin.UnifiedSigninSetupForm'>, us_setup_validate_form=<class 'flask_security.unified_signin.UnifiedSigninSetupValidateForm'>, us_verify_form=<class 'flask_security.unified_signin.UnifiedVerifyForm'>, wan_register_form=<class 'flask_security.webauthn.WebAuthnRegisterForm'>, wan_register_response_form=<class 'flask_security.webauthn.WebAuthnRegisterResponseForm'>, wan_signin_form=<class 'flask_security.webauthn.WebAuthnSigninForm'>, wan_signin_response_form=<class 'flask_security.webauthn.WebAuthnSigninResponseForm'>, wan_delete_form=<class 'flask_security.webauthn.WebAuthnDeleteForm'>, wan_verify_form=<class 'flask_security.webauthn.WebAuthnVerifyForm'>, mail_util_cls=<class 'flask_security.mail_util.MailUtil'>, password_util_cls=<class 'flask_security.password_util.PasswordUtil'>, phone_util_cls=<class 'flask_security.phone_util.PhoneUtil'>, render_template=<function default_render_template>, totp_cls=<class 'flask_security.totp.Totp'>, username_util_cls=<class 'flask_security.username_util.UsernameUtil'>, webauthn_util_cls=<class 'flask_security.webauthn_util.WebauthnUtil'>, mf_recovery_codes_util_cls=<class 'flask_security.recovery_codes.MfRecoveryCodesUtil'>, oauth=None, **kwargs)

   The "Security" class initializes the Flask-Security extension.

   Parameters:
      * **app** (*flask.Flask** | **None*) -- The application.

      * **datastore** (*UserDatastore** | **None*) -- An instance of a
        user datastore.

      * **register_blueprint** (*bool*) -- to register the Security
        blueprint or not.

      * **login_form** (*t.Type**[**LoginForm**]*) -- set form for the
        login view

      * **verify_form** (*t.Type**[**VerifyForm**]*) -- set form for
        re-authentication due to freshness check

      * **register_form** (*t.Type**[**RegisterForm**]*) -- set form
        for the register view when *SECURITY_CONFIRMABLE* is false

      * **confirm_register_form**
        (*t.Type**[**ConfirmRegisterForm**]*) -- set form for the
        register view when *SECURITY_CONFIRMABLE* is true

      * **forgot_password_form** (*t.Type**[**ForgotPasswordForm**]*)
        -- set form for the forgot password view

      * **reset_password_form** (*t.Type**[**ResetPasswordForm**]*) --
        set form for the reset password view

      * **change_password_form** (*t.Type**[**ChangePasswordForm**]*)
        -- set form for the change password view

      * **send_confirmation_form**
        (*t.Type**[**SendConfirmationForm**]*) -- set form for the
        send confirmation view

      * **passwordless_login_form**
        (*t.Type**[**PasswordlessLoginForm**]*) -- set form for the
        passwordless login view

      * **two_factor_setup_form** (*t.Type**[**TwoFactorSetupForm**]*)
        -- set form for the 2FA setup view

      * **two_factor_verify_code_form**
        (*t.Type**[**TwoFactorVerifyCodeForm**]*) -- set form the the
        2FA verify code view

      * **two_factor_rescue_form**
        (*t.Type**[**TwoFactorRescueForm**]*) -- set form for the 2FA
        rescue view

      * **two_factor_select_form**
        (*t.Type**[**TwoFactorSelectForm**]*) -- set form for
        selecting between active 2FA methods

      * **mf_recovery_codes_form**
        (*t.Type**[**MfRecoveryCodesForm**]*) -- set form for
        retrieving and setting recovery codes

      * **mf_recovery_form** (*t.Type**[**MfRecoveryForm**]*) -- set
        form for multi factor recovery

      * **us_signin_form** (*t.Type**[**UnifiedSigninForm**]*) -- set
        form for the unified sign in view

      * **us_setup_form** (*t.Type**[**UnifiedSigninSetupForm**]*) --
        set form for the unified sign in setup view

      * **us_setup_validate_form**
        (*t.Type**[**UnifiedSigninSetupValidateForm**]*) -- set form
        for the unified sign in setup validate view

      * **us_verify_form** (*t.Type**[**UnifiedVerifyForm**]*) -- set
        form for re-authenticating due to freshness check

      * **wan_register_form** (*t.Type**[**WebAuthnRegisterForm**]*)
        -- set form for registering a webauthn security key

      * **wan_register_response_form**
        (*t.Type**[**WebAuthnRegisterResponseForm**]*) -- set form for
        registering a webauthn security key

      * **wan_signin_form** (*t.Type**[**WebAuthnSigninForm**]*) --
        set form for authenticating with a webauthn security key

      * **wan_signin_response_form**
        (*t.Type**[**WebAuthnSigninResponseForm**]*) -- set form for
        authenticating with a webauthn

      * **wan_delete_form** (*t.Type**[**WebAuthnDeleteForm**]*) --
        set form for deleting a webauthn security key

      * **wan_verify_form** (*t.Type**[**WebAuthnVerifyForm**]*) --
        set form for using a webauthn key to verify authenticity

      * **mail_util_cls** (*t.Type**[**MailUtil**]*) -- Class to use
        for sending emails. Defaults to "MailUtil"

      * **password_util_cls** (*t.Type**[**PasswordUtil**]*) -- Class
        to use for password normalization/validation. Defaults to
        "PasswordUtil"

      * **phone_util_cls** (*t.Type**[**PhoneUtil**]*) -- Class to use
        for phone number utilities. Defaults to "PhoneUtil"

      * **render_template** (*t.Callable**[**...**, **str**]*) --
        function to use to render templates. The default is Flask's
        render_template() function.

      * **totp_cls** (*t.Type**[**Totp**]*) -- Class to use as TOTP
        factory. Defaults to "Totp"

      * **username_util_cls** (*t.Type**[**UsernameUtil**]*) -- Class
        to use for normalizing and validating usernames. Defaults to
        "UsernameUtil"

      * **webauthn_util_cls** (*t.Type**[**WebauthnUtil**]*) -- Class
        to use for customizing WebAuthn registration and signin.
        Defaults to "WebauthnUtil"

      * **mf_recovery_codes_util_cls**
        (*t.Type**[**MfRecoveryCodesUtil**]*) -- Class for generating,
        checking, encrypting and decrypting recovery codes. Defaults
        to "MfRecoveryCodesUtil"

      * **oauth** (*OAuth** | **None*) -- An instance of
        authlib.integrations.flask_client.OAuth. If not set, Flask-
        Security will create one.

      * **kwargs** (*t.Any*)

   Tip:

     Be sure that all your configuration values have been set PRIOR to
     instantiating this class. Some configuration values are set as
     attributes on the instance and therefore won't track any changes.

   Added in version 3.4.0: "verify_form" added as part of freshness
   /re-authentication

   Added in version 3.4.0: "us_signin_form", "us_setup_form",
   "us_setup_validate_form", and "us_verify_form" added as part of the
   Unified Sign In feature.

   Added in version 3.4.0: "totp_cls" added to enable applications to
   implement replay protection - see "Totp".

   Added in version 3.4.0: "phone_util_cls" added to allow different
   phone number  parsing implementations - see "PhoneUtil"

   Added in version 4.0.0: "mail_util_cls" added to isolate mailing
   handling. "password_util_cls" added to encapsulate password
   validation/normalization.

   Added in version 4.1.0: "username_util_cls" added to encapsulate
   username handling.

   Added in version 5.0.0: "wan_register_form",
   "wan_register_response_form",  "webauthn_signin_form",
   "wan_signin_response_form",  "webauthn_delete_form",
   "webauthn_verify_form", "tf_select_form".

   Added in version 5.0.0: "WebauthnUtil" class.

   Added in version 5.0.0: Added support for multi-factor recovery
   codes "mf_recovery_codes_form", "mf_recovery_form".

   Added in version 5.1.0: "mf_recovery_codes_util_cls", "oauth"

   Deprecated since version 4.0.0: "send_mail" and "send_mail_task".
   Replaced with "mail_util_cls". "two_factor_verify_password_form"
   removed. "password_validator" removed in favor of the new
   "password_util_cls".

   Deprecated since version 5.0.0: Passing in a LoginManager instance.
   Removed in 5.1.0

   Deprecated since version 5.0.0: json_encoder_cls is no longer
   honored since Flask 2.2 has deprecated it.

   Deprecated since version 5.3.1: Passing in an anonymous_user class.
   Removed in 5.4.0

   init_app(app, datastore=None, register_blueprint=None, **kwargs)

      Initializes the Flask-Security extension for the specified
      application and datastore implementation.

      Parameters:
         * **app** (*flask.Flask*) -- The application.

         * **datastore** (*UserDatastore** | **None*) -- An instance
           of a user datastore.

         * **register_blueprint** (*bool** | **None*) -- to register
           the Security blueprint or not.

         * **kwargs** (*t.Any*) -- Can be used to override/initialize
           any of the form names, flags, and utility classes. All
           other kwargs are ignored.

      Return type:
         None

      If you create the Security instance with both an 'app' and
      'datastore' you shouldn't call this - it will be called as part
      of the constructor.

   reauthn_handler(cb)

      Callback when endpoint required a fresh authentication. This is
      called by "auth_required()".

      Parameters:
         **cb** (*t.Callable**[**[**timedelta**, **timedelta**]**,
         **ResponseValue**]*) --

         Callback function with signature (within, grace)

         within:
            timedelta that endpoint required fresh authentication
            within.

         grace:
            timedelta of grace period that endpoint allowed.

      Return type:
         None

      Should return a Response or something Flask can create a
      Response from. Can raise an exception if it is handled as part
      of "flask.errorhandler(<exception>)"

      The default implementation will return a 401 response if the
      request was JSON, otherwise will redirect to
      "SECURITY_US_VERIFY_URL" (if "SECURITY_UNIFIED_SIGNIN" is
      enabled) else to "SECURITY_VERIFY_URL". If both of those are
      None it sends an "abort(401)".

      See "flask_security.auth_required()" for details about freshness
      checking.

      Added in version 3.4.0.

   render_json(cb)

      Callback to render response payload as JSON.

      Parameters:
         **cb** (*t.Callable**[**[**dict**[**str**, **t.Any**]**,
         **int**, **dict**[**str**, **str**] **| **None**, **User** |
         **None**]**, **ResponseValue**]*) --

         Callback function with signature (payload, code,
         headers=None, user=None)

            payload:
               A dict. Please see the formal API spec for details.

            code:
               Http status code

            headers:
               Headers object

            user:
               the UserDatastore object (or None). Note that this is
               usually the same as current_user - but not always.

      Return type:
         None

      The default implementation simply returns:

         headers["Content-Type"] = "application/json"
         payload = dict(meta=dict(code=code), response=payload)
         return make_response(jsonify(payload), code, headers)

      Important:

        Note that this has nothing to do with how the response is
        serialized. That is controlled by Flask and starting with
        Flask 2.2 that is managed by sub-classing Flask::JSONProvider.
        Flask-Security does this to add serializing lazy-strings.

      This can be used by applications to unify all their JSON API
      responses. This is called in a request context and should return
      a Response or something Flask can create a Response from.

      Added in version 3.3.0.

   set_form_info(name, form_info)

      Set form instantiation info.

      Parameters:
         * **name** (*str*) -- Name of form.

         * **form_info** (*FormInfo*) -- see "FormInfo"

      Return type:
         None

      Advanced: Forms (which are all FlaskForms) are instantiated at
      the start of each request. Normally this is done as part of a
      view by simply calling the form class constructor - Flask-
      WTForms handles filling it in from various request
      attributes.The form classes themselves can be extended (e.g. to
      add or change fields) and the derived class can be set at
      *Security* constructor time, *init_app* time, or using this
      method.This default implementation is suitable for most
      applications.Some application might want to control the
      instantiation of forms, for example to be able to inject
      additional validation services. Using this method, a callable
      *instantiator* can be set that Flask-Security will call to
      return a properly instantiated form.

      Danger:

        Do not perform any validation as part of instantiation - many
        views have a bunch of logic PRIOR to calling the form
        validator.

        Added in version 5.1.0.

   unauthn_handler(cb)

      Callback for failed authentication. This is called by
      "auth_required()", "auth_token_required()" or
      "http_auth_required()" if authentication fails. It is also
      called from Flask-Login's @login_required decorator.

      Parameters:
         **cb** (*t.Callable**[**[**list**[**str**]**,
         **dict**[**str**, **str**] **| **None**]**,
         **ResponseValue**]*) --

         Callback function with signature (mechanisms=None,
         headers=None)

         mechanisms:
            List of which authentication mechanisms were tried

         headers:
            dict of headers to return

      Return type:
         None

      Should return a Response or something Flask can create a
      Response from. Can raise an exception if it is handled as part
      of "flask.errorhandler(<exception>)"

      The default implementation will return a 401 response if the
      request was JSON, otherwise will redirect to the *login* view.

      Added in version 3.3.0.

      Changed in version 5.4.0: No longer calls Flask-Login and has
      complete logic built-in.

   unauthz_handler(cb)

      Callback for failed authorization. This is called by the
      "roles_required()", "roles_accepted()",
      "permissions_required()", or "permissions_accepted()" if a role
      or permission is missing.

      Parameters:
         **cb** (*t.Callable**[**[**str**, **list**[**str**] **|
         **None**]**, **ResponseValue**]*) --

         Callback function with signature (func, params)

         func_name:
            the decorator function name (e.g. 'roles_required')

         params:
            list of what (if any) was passed to the decorator.

      Return type:
         None

      Should return a Response or something Flask can create a
      Response from. Can raise an exception if it is handled as part
      of flask.errorhandler(<exception>)

      With the passed parameters the application could deliver a
      concise error message.

      Added in version 3.3.0.

      Changed in version 5.1.0: Pass in the function name, not the
      function!

   want_json(fn)

      Function that returns True if response should be JSON (based on
      the request)

      Parameters:
         **fn** (*t.Callable**[**[**flask.Request**]**, **bool**]*) --

         Function with the following signature (request)

         request:
            Werkzueg/Flask request

      Return type:
         None

      The default implementation returns True if either the Content-
      Type is "application/json" or the best Accept header value is
      "application/json".

      Added in version 3.3.0.

flask_security.current_user

   A proxy for the current user.


Protecting Views
================

All Flask-Security decorators are compatible with Flask's async
implementation. This is accomplished by wrapping function calls with
flask.ensure_async(). Please see Flask async.

flask_security.anonymous_user_required(f)

   Decorator which requires that caller NOT be logged in. If a logged
   in user accesses an endpoint protected with this decorator they
   will be redirected to the "SECURITY_POST_LOGIN_VIEW". If the caller
   requests a JSON response, a 400 will be returned.

   Changed in version 3.3.0: Support for JSON response was added.

   Parameters:
      **f** (*Callable**[**[**...**]**, **Any**]*)

   Return type:
      *Callable*[[...], *Any*]

flask_security.http_auth_required(realm)

   Decorator that protects endpoints using Basic HTTP authentication.

   Parameters:
      **realm** (*Any*) -- optional realm name

   Return type:
      *Callable*[[...], *Any*]

   If authentication fails, then a 401 with the 'WWW-Authenticate'
   header set will be returned.

   Once authenticated, if so configured, CSRF protection will be
   tested.

flask_security.auth_token_required(fn)

   Decorator that protects endpoints using token authentication. The
   token should be added to the request by the client by using a query
   string variable with a name equal to the configuration value of
   "SECURITY_TOKEN_AUTHENTICATION_KEY" or in a request header named
   that of the configuration value of
   "SECURITY_TOKEN_AUTHENTICATION_HEADER"

   Once authenticated, if so configured, CSRF protection will be
   tested.

   Parameters:
      **fn** (*Callable**[**[**...**]**, **Any**]*)

   Return type:
      *Callable*[[...], *Any*]

flask_security.auth_required(*auth_methods, within=-1, grace=None)

   Decorator that protects endpoints through multiple mechanisms.
   Example:

      @app.route('/dashboard')
      @auth_required('token', 'session')
      def dashboard():
          return 'Dashboard'

   Parameters:
      * **auth_methods** (*str** | **Callable**[**[**]**,
        **list**[**str**]**] **| **None*) -- Specified mechanisms
        (token, basic, session). If not specified then all current
        available mechanisms (except "basic") will be tried. A
        callable can also be passed (useful if you need app/request
        context). The callable must return a list.

      * **within** (*int** | **float** | **Callable**[**[**]**,
        **timedelta**]*) --

        Add 'freshness' check to authentication. Is either an int
        specifying # of minutes, or a callable that returns a
        timedelta. For timedeltas, timedelta.total_seconds() is used
        for the calculations:

           * If > 0, then the caller must have authenticated within
             the time specified (as measured using the session
             cookie).

           * If 0 and not within the grace period (see below) the
             caller will always be redirected to re-authenticate.

           * If < 0 (the default) no freshness check is performed.

        Note that Basic Auth, by definition, is always 'fresh' and
        will never result in a redirect/error.

      * **grace** (*int** | **float** | **Callable**[**[**]**,
        **timedelta**] **| **None*) -- Add a grace period for
        freshness checks. As above, either an int or a callable
        returning a timedelta. If not specified then
        "SECURITY_FRESHNESS_GRACE_PERIOD" is used. The grace period
        allows callers to complete the required operations w/o being
        prompted again. See
        "flask_security.check_and_update_authn_fresh()" for details.

   Return type:
      *Callable*[[...], *Any*]

   Note that regardless of order specified - they will be tried in the
   following order: token, session, basic.

   The first mechanism that succeeds is used, following that,
   depending on configuration, CSRF protection will be tested.

   On authentication failure "Security.unauthn_handler()" will be
   called.

   As a side effect, upon successful authentication, the request
   global
      "fs_authn_via" will be set to the method ("basic", "token",
      "session")

   Note:

     If "basic" is specified in addition to other methods, then if
     authentication fails, a 401 with the "WWW-Authenticate" header
     will be returned - rather than being redirected to the login
     view.

   Changed in version 3.3.0: If "auth_methods" isn't specified, then
   all will be tried. Authentication mechanisms will always be tried
   in order of "token", "session", "basic" regardless of how they are
   specified in the "auth_methods" parameter.

   Changed in version 3.4.0: Added "within" and "grace" parameters to
   enforce a freshness check.

   Changed in version 3.4.4: If "auth_methods" isn't specified try all
   mechanisms EXCEPT "basic".

   Changed in version 4.0.0: auth_methods can be passed as a callable.

flask_security.roles_required(*roles)

   Decorator which specifies that a user must have all the specified
   roles. Example:

      @app.route('/dashboard')
      @roles_required('admin', 'editor')
      def dashboard():
          return 'Dashboard'

   The current user must have both the *admin* role and *editor* role
   in order to view the page.

   Parameters:
      **roles** (*str*) -- The required roles.

   Return type:
      *Callable*[[...], *Any*]

flask_security.roles_accepted(*roles)

   Decorator which specifies that a user must have at least one of the
   specified roles. Example:

      @app.route('/create_post')
      @roles_accepted('editor', 'author')
      def create_post():
          return 'Create Post'

   The current user must have either the *editor* role or *author*
   role in order to view the page.

   Parameters:
      **roles** (*str*) -- The possible roles.

   Return type:
      *Callable*[[...], *Any*]

flask_security.permissions_required(*fsperms)

   Decorator which specifies that a user must have all the specified
   permissions. Example:

      @app.route('/dashboard')
      @permissions_required('admin-write', 'editor-write')
      def dashboard():
          return 'Dashboard'

   The current user must have BOTH permissions (via the roles it has)
   to view the page.

   N.B. Don't confuse these permissions with flask-principle
   Permission()!

   Parameters:
      **fsperms** (*str*) -- The required permissions.

   Return type:
      *Callable*[[...], *Any*]

   Added in version 3.3.0.

flask_security.permissions_accepted(*fsperms)

   Decorator which specifies that a user must have at least one of the
   specified permissions. Example:

      @app.route('/create_post')
      @permissions_accepted('editor-write', 'author-wrote')
      def create_post():
          return 'Create Post'

   The current user must have one of the permissions (via the roles it
   has) to view the page.

   N.B. Don't confuse these permissions with flask-principle
   Permission()!

   Parameters:
      **fsperms** (*str*) -- The possible permissions.

   Return type:
      *Callable*[[...], *Any*]

   Added in version 3.3.0.

flask_security.unauth_csrf(fall_through=False)

   Decorator for endpoints that don't need authentication but do want
   CSRF checks (available via Header rather than just form). This is
   required when setting *WTF_CSRF_CHECK_DEFAULT* = **False** since in
   that case, without this decorator, the form validation will attempt
   to do the CSRF check, and that will fail since the csrf-token is in
   the header (for pure JSON requests).

   This decorator does nothing unless Flask-WTF::CSRFProtect has been
   initialized.

   This decorator does nothing if *WTF_CSRF_ENABLED* == **False**.

   This decorator does nothing if the caller is authenticated.

   This decorator will suppress CSRF if caller isn't authenticated and
   has set the "SECURITY_CSRF_IGNORE_UNAUTH_ENDPOINTS" config variable
   to **True**.

   Added in version 3.3.0.

   Changed in version 5.4.3: The fall_through parameter is now
   ignored. Add code to properly handle JSON errors.

   Parameters:
      **fall_through** (*bool*)

   Return type:
      *Callable*[[...], *Any*]

flask_security.handle_csrf(method, json_response=False)

   Invoke CSRF protection based on authentication method.

   Usually this is called as part of a decorator, but if that isn't
   appropriate, endpoint code can call this directly.

   If CSRF protection is appropriate, this will call
   flask_wtf::protect() which will raise a CSRFError(BadRequest) on
   CSRF failure.

   This routine does nothing if any of these are true:

      1. *WTF_CSRF_ENABLED* is set to False

      2. the Flask-WTF CSRF module hasn't been initialized

      3. csrfProtect already checked and accepted the token

   This means in the default config - CSRF is done as part of form
   validation not here. Only if the application calls CSRFProtect(app)
   will this method do anything. Furthermore - since this is called
   PRIOR to form instantiation if the request is JSON - it MUST send
   the csrf_token as a header.

   If the passed in method is not in
   "SECURITY_CSRF_PROTECT_MECHANISMS" then in addition to no CSRF code
   being run, the flask_wtf request global 'csrf_valid' will be set so
   that downstream code knows to ignore any CSRF checks.

   Returns None if all ok, returns a Response with JSON error if
   request wanted JSON - else re-raises the CSRFError exception.

   Added in version 3.3.0.

   Changed in version 5.4.3: Use flask_wtf request global 'csrf_valid'
   instead of our own to handle application forms that aren't derived
   from our forms.

   Parameters:
      * **method** (*str*)

      * **json_response** (*bool*)

   Return type:
      ResponseValue | None


User Object Helpers
===================

class flask_security.UserMixin

   Mixin for *User* model definitions

   augment_auth_token(tdata)

      Override this to add/modify parts of the auth token. Additions
      to the dict can be made and verified in verify_auth_token()

      Added in version 5.4.0.

      Parameters:
         **tdata** (*dict**[**str**, **Any**]*)

      Return type:
         None

   calc_username()

      Come up with the best 'username' based on how the app is
      configured (via "SECURITY_USER_IDENTITY_ATTRIBUTES"). Returns
      the first non-null match (and converts to string). In theory
      this should NEVER be the empty string unless the user record
      isn't actually valid.

      Added in version 3.4.0.

      Return type:
         str

   get_auth_token()

      Constructs the user's authentication token.

      Raises:
         **ValueError** -- If "fs_token_uniquifier" is part of model
         but not set.

      Return type:
         str | bytes

      Optionally use a separate uniquifier so that changing password
      doesn't invalidate auth tokens.

      The returned value is securely signed using the
      "remember_token_serializer"

      Changed in version 4.0.0: If user model has
      "fs_token_uniquifier" - use that (raise ValueError if not set).
      Otherwise, fallback to using "fs_uniquifier".

      Changed in version 5.4.0: New format - a dict with a version
      string. Add a token-based expiry option as well as a session id.

   get_id()

      Returns the user identification attribute. 'Alternative-token'
      for Flask-Login. This is always "fs_uniquifier".

      Added in version 3.4.0.

      Return type:
         str

   get_redirect_qparams(existing=None)

      Return user info that will be added to redirect query params.

      Parameters:
         **existing** (*dict**[**str**, **Any**] **| **None*) -- A
         dict that will be updated.

      Returns:
         A dict whose keys will be query params and values will be
         query values.

      Return type:
         dict[str, *Any*]

      The returned dict will always have an 'identity' key/value. If
      the User Model contains 'email', an 'email' key/value will be
      added. All keys provided in 'existing' will also be merged in.

      Added in version 3.2.0.

      Changed in version 4.0.0: Add 'identity' using
      UserMixin.calc_username() - email is optional.

   get_security_payload()

      Serialize user object as response payload. Override this to
      return any/all of the user object in JSON responses. Return a
      dict.

      Return type:
         dict[str, *Any*]

   has_permission(permission)

      Returns *True* if user has this permission (via a role it has).

      Parameters:
         **permission** (*str*) -- permission string name

      Return type:
         bool

      Added in version 3.3.0.

   has_role(role)

      Returns *True* if the user identifies with the specified role.

      Parameters:
         **role** (*str** | **Role*) -- A role name or *Role* instance

      Return type:
         bool

   property is_active: bool

      Returns *True* if the user is active.

   tf_send_security_token(method, **kwargs)

      Generate and send the security code for two-factor.

      Parameters:
         * **method** (*str*) -- The method in which the code will be
           sent

         * **kwargs** (*Any*) -- Opaque parameters that are subject to
           change at any time

      Returns:
         None if successful, error message if not.

      Return type:
         str | None

      This is a wrapper around "tf_send_security_token()" that can be
      overridden to manage any errors.

      Added in version 3.4.0.

   us_send_security_token(method, **kwargs)

      Generate and send the security code for unified sign in.

      Parameters:
         * **method** (*str*) -- The method in which the code will be
           sent

         * **kwargs** (*Any*) -- Opaque parameters that are subject to
           change at any time

      Returns:
         None if successful, error message if not.

      Return type:
         str | None

      This is a wrapper around "us_send_security_token()" that can be
      overridden to manage any errors.

      Added in version 3.4.0.

   verify_and_update_password(password)

      Returns "True" if the password is valid for the specified user.

      Additionally, the hashed password in the database is updated if
      the hashing algorithm happens to have changed.

      N.B. you MUST call DB commit if you are using a session-based
      datastore (such as SqlAlchemy) since the user instance might
      have been altered (i.e. "app.security.datastore.commit()"). This
      is usually handled in the view.

      Parameters:
         **password** (*str*) -- A plaintext password to verify

      Return type:
         bool

      Added in version 3.2.0.

   verify_auth_token(tdata)

      Override this to perform additional verification of contents of
      auth token. Prior to this being called the token has been
      validated (via signing) and has not expired (either with MAX_AGE
      or specific 'exp' value).

      Parameters:
         **tdata** (*dict**[**str**, **Any**]*) -- a dictionary just
         as in augment_auth_token()

      Returns:
         True if auth token represented by tdata is valid, False
         otherwise.

      Return type:
         bool

      Added in version 3.3.0.

      Changed in version 5.4.0: Now receives a dictionary.

class flask_security.RoleMixin

   Mixin for *Role* model definitions

   get_permissions()

      Return set of permissions associated with role.

      Added in version 3.3.0.

      Return type:
         set

class flask_security.WebAuthnMixin

   get_user_mapping()

      Return the filter needed by find_user() to get the user
      associated with this webauthn credential. Note that this
      probably has to be overridden using mongoengine.

      Added in version 5.0.0.

      Return type:
         dict[str, *Any*]


Datastores
==========

class flask_security.UserDatastore(user_model, role_model, webauthn_model=None)

   Abstracted user datastore.

   Parameters:
      * **user_model** (*t.Type**[**User**]*) -- A user model class
        definition

      * **role_model** (*t.Type**[**Role**]*) -- A role model class
        definition

      * **webauthn_model** (*t.Type**[**WebAuthn**] **| **None*) -- A
        model used to store webauthn registrations

   Important:

     For mutating operations, the user/role will be added to the
     datastore (by calling self.put(<object>). If the datastore is
     session based (such as for SQLAlchemyDatastore) it is up to
     caller to actually commit the transaction by calling
     datastore.commit().

   Note:

     You must implement get_user_mapping in your WebAuthn model if
     your User model doesn't have a primary key Column called 'id'

   activate_user(user)

      Activates a specified user. Returns *True* if a change was made.

      Parameters:
         **user** (*User*) -- The user to activate

      Return type:
         bool

   add_permissions_to_role(role, permissions)

      Add one or more permissions to role.

      Parameters:
         * **role** (*Role** | **str*) -- The role to modify. Can be a
           Role object or string role name

         * **permissions** (*set** | **list** | **tuple** | **str*) --
           a set, list, tuple or comma separated string.

      Returns:
         True if permissions added, False if role doesn't exist.

      Return type:
         bool

      Caller must commit to DB.

      Added in version 4.0.0.

   add_role_to_user(user, role)

      Adds a role to a user.

      Parameters:
         * **user** (*User*) -- The user to manipulate.

         * **role** (*Role** | **str*) -- The role to add to the user.
           Can be a Role object or string role name

      Returns:
         True is role was added, False if role already existed.

      Return type:
         bool

   create_role(**kwargs)

      Creates and returns a new role from the given parameters.
      Supported params (depending on RoleModel):

      Parameters:
         * **name** -- Role name

         * **permissions** --

           a list, set, tuple or comma separated string. These are
           user-defined strings that correspond to args used with
           @permissions_required()

           Added in version 3.3.0.

         * **kwargs** (*t.Any*)

      Return type:
         Role

   create_user(**kwargs)

      Creates and returns a new user from the given parameters.

      Parameters:
         * **email** -- required.

         * **password** -- Hashed password.

         * **roles** -- list of roles to be added to user. Can be Role
           objects or strings

         * **kwargs** (*t.Any*)

      Return type:
         User

      Any other element of the User data model may be supplied as
      well.

      Note:

        No normalization is done on email - it is assumed the caller
        has already done that.Best practice is:

           try:
               enorm = app.security._mail_util.validate(email)
           except ValueError:

      Danger:

        Be aware that whatever *password* is passed in will be stored
        directly in the DB. Do NOT pass in a plaintext password! Best
        practice is to pass in
        "hash_password(plaintext_password)".Furthermore, no validation
        nor normalization is done on the password (e.g for minimum
        length).Best practice is:

           pbad, pnorm = app.security._password_util.validate(password, True)

        Look for *pbad* being None. Pass the normalized password
        *pnorm* to this method.

      The new user's "active" property will be set to "True" unless
      explicitly set to "False" in *kwargs* (e.g. active = False)

   deactivate_user(user)

      Deactivates a specified user. Returns *True* if a change was
      made.

      This will immediately disallow access to all endpoints that
      require authentication either via session or tokens. The user
      will not be able to log in again.

      Parameters:
         **user** (*User*) -- The user to deactivate

      Return type:
         bool

   delete_user(user)

      Deletes the specified user.

      Parameters:
         **user** (*User*) -- The user to delete

      Return type:
         None

   delete_webauthn(webauthn)

      Parameters:
         **webauthn** (*WebAuthn*)

      Return type:
         None

   find_or_create_role(name, **kwargs)

      Returns a role matching the given name or creates it with any
      additionally provided parameters.

      Parameters:
         * **name** (*str*)

         * **kwargs** (*t.Any*)

      Return type:
         Role

   find_role(role)

      Returns a role matching the provided name.

      Parameters:
         **role** (*str*)

      Return type:
         Role | None

   find_user(**kwargs)

      Returns a user matching the provided parameters. Besides keyword
      arguments used to filter the results, 'case_insensitive' can be
      passed (defaults to False)

      Parameters:
         **kwargs** (*t.Any*)

      Return type:
         User | None

   find_webauthn(credential_id)

      Returns a credential matching the id.

      Parameters:
         **credential_id** (*bytes*)

      Return type:
         WebAuthn | None

   remove_permissions_from_role(role, permissions)

      Remove one or more permissions from a role.

      Parameters:
         * **role** (*Role** | **str*) -- The role to modify. Can be a
           Role object or string role name

         * **permissions** (*set** | **list** | **tuple** | **str*) --
           a set, list, tuple or a comma separated string.

      Returns:
         True if permissions removed, False if role doesn't exist.

      Return type:
         bool

      Caller must commit to DB.

      Added in version 4.0.0.

   remove_role_from_user(user, role)

      Removes a role from a user.

      Parameters:
         * **user** (*User*) -- The user to manipulate. Can be an User
           object or email

         * **role** (*Role** | **str*) -- The role to remove from the
           user. Can be a Role object or string role name

      Returns:
         True if role was removed, False if role doesn't exist or user
         didn't have role.

      Return type:
         bool

   reset_user_access(user)

      Use this method to reset user authentication methods in the case
      of compromise. This will:

         * reset fs_uniquifier - which causes session cookie, remember
           cookie, auth tokens to be unusable

         * reset fs_token_uniquifier (if present) - cause auth tokens
           to be unusable

         * remove all unified signin TOTP secrets so those can't be
           used

         * remove all two-factor secrets so those can't be used

         * remove all registered webauthn credentials

         * remove all one-time recovery codes

         * will NOT affect password

      Note that if using unified sign in and allow 'email' as a way to
      receive a code; this will also get reset. If the user registered
      w/o a password then they likely will have no way to
      authenticate.

      Note - this method isn't used directly by Flask-Security - it is
      provided as a helper for an application's administrative needs.

      Remember to call commit on DB if needed.

      Added in version 3.4.1.

      Changed in version 5.0.0: Added webauthn and recovery codes
      reset.

      Parameters:
         **user** (*User*)

      Return type:
         None

   set_token_uniquifier(user, uniquifier=None)

      Set user's auth token identity key. This will immediately render
      outstanding auth tokens invalid.

      Parameters:
         * **user** (*User*) -- User to modify

         * **uniquifier** (*str** | **None*) -- Unique value - if none
           then uuid.uuid4().hex is used

      Return type:
         None

      This method is a no-op if the user model doesn't contain the
      attribute "fs_token_uniquifier"

      Added in version 4.0.0.

   set_uniquifier(user, uniquifier=None)

      Set user's Flask-Security identity key. This will immediately
      render outstanding auth tokens, session cookies and remember
      cookies invalid.

      Parameters:
         * **user** (*User*) -- User to modify

         * **uniquifier** (*str** | **None*) -- Unique value - if none
           then uuid.uuid4().hex is used

      Return type:
         None

      Added in version 3.3.0.

   tf_reset(user)

      Disable two-factor auth for user.

      Parameters:
         **user** (*User*)

      Return type:
         None

   tf_set(user, primary_method, totp_secret=None, phone=None)

      Set two-factor info into user record. This carefully only
      changes things if different.

      If totp_secret isn't provided - existing one won't be changed.
      If phone isn't provided, the existing phone number won't be
      changed.

      This could be called from an application to apiori setup a user
      for two factor without the user having to go through the setup
      process.

      To get a totp_secret - use
      "app.security._totp_factory.generate_totp_secret()"

      Parameters:
         * **user** (*User*)

         * **primary_method** (*str*)

         * **totp_secret** (*str** | **None*)

         * **phone** (*str** | **None*)

      Return type:
         None

   toggle_active(user)

      Toggles a user's active status. Always returns True.

      Parameters:
         **user** (*User*)

      Return type:
         bool

   us_reset(user, method=None)

      Disable unified sign in for user. This will disable
      authenticator app and SMS, and email. N.B. if user has no
      password they may not be able to authenticate at all.

      Added in version 3.4.1.

      Changed in version 5.0.0: Added optional method argument to
      delete just a single method

      Parameters:
         * **user** (*User*)

         * **method** (*str** | **None*)

      Return type:
         None

   us_set(user, method, totp_secret=None, phone=None)

      Set unified sign in info into user record.

      If totp_secret isn't provided - existing one won't be changed.
      If phone isn't provided, the existing phone number won't be
      changed.

      This could be called from an application to apiori setup a user
      for unified sign in without the user having to go through the
      setup process.

      To get a totp_secret - use
      "app.security._totp_factory.generate_totp_secret()"

      Added in version 3.4.1.

      Parameters:
         * **user** (*User*)

         * **method** (*str*)

         * **totp_secret** (*str** | **None*)

         * **phone** (*str** | **None*)

      Return type:
         None

   webauthn_reset(user)

      Reset access via webauthn credentials. This will DELETE all
      registered credentials. There doesn't appear to be any reason to
      change the user's fs_webauthn_user_handle.

      Parameters:
         **user** (*User*)

      Return type:
         None

class flask_security.SQLAlchemyUserDatastore(db, user_model, role_model, webauthn_model=None)

   Bases: "SQLAlchemyDatastore", "UserDatastore"

   A UserDatastore implementation that assumes the use of Flask-
   SQLAlchemy for datastore transactions.

   Parameters:
      * **db** (*flask_sqlalchemy.SQLAlchemy*)

      * **user_model** (*t.Type**[**User**]*) -- See Models.

      * **role_model** (*t.Type**[**Role**]*) -- See Models.

      * **webauthn_model** (*t.Type**[**WebAuthn**] **| **None*) --
        See Models.

class flask_security.SQLAlchemySessionUserDatastore(session, user_model, role_model, webauthn_model=None)

   Bases: "SQLAlchemyUserDatastore", "SQLAlchemyDatastore"

   A UserDatastore implementation that directly uses SQLAlchemy's
   session API.

   Parameters:
      * **session** (*sqlalchemy.orm.scoping.scoped_session*)

      * **user_model** (*t.Type**[**User**]*) -- See Models.

      * **role_model** (*t.Type**[**Role**]*) -- See Models.

      * **webauthn_model** (*t.Type**[**WebAuthn**] **| **None*) --
        See Models.

class flask_security.MongoEngineUserDatastore(db, user_model, role_model, webauthn_model=None)

   Bases: "MongoEngineDatastore", "UserDatastore"

   A UserDatastore implementation that assumes the use of MongoEngine
   for datastore transactions.

   Parameters:
      * **db** (*mongoengine.connection*)

      * **user_model** (*t.Type**[**User**]*) -- See Models.

      * **role_model** (*t.Type**[**Role**]*) -- See Models.

      * **webauthn_model** (*t.Type**[**WebAuthn**] **| **None*) --
        See Models.

class flask_security.PeeweeUserDatastore(db, user_model, role_model, role_link, webauthn_model=None)

   Bases: "PeeweeDatastore", "UserDatastore"

   A UserDatastore implementation that assumes the use of Peewee Flask
   utils for datastore transactions.

class flask_security.PonyUserDatastore(db, user_model, role_model, webauthn_model=None)

   Bases: "PonyDatastore", "UserDatastore"

   A UserDatastore implementation that assumes the use of PonyORM for
   datastore transactions.

   Code primarily from https://github.com/ET-CS but taken over after
   being abandoned.

   Parameters:
      * **db**

      * **user_model** -- See Models.

      * **role_model** -- See Models.

      * **webauthn_model** -- See Models.

class flask_security.datastore.SQLAlchemyDatastore(db)

   Internal class implementing DataStore interface.

class flask_security.datastore.MongoEngineDatastore(db)

   Internal class implementing DataStore interface.

class flask_security.datastore.PeeweeDatastore(db)

   Internal class implementing DataStore interface.

class flask_security.datastore.PonyDatastore(db)

   Internal class implementing DataStore interface.

class User

   The User model. This must be provided by the application. See
   Models.

class Role

   The Role model. This must be provided by the application. See
   Models.

class WebAuthn

   The WebAuthn model. This must be provided by the application. See
   Models.


Packaged Models
===============


Utils
=====

flask_security.lookup_identity(identity)

   Lookup identity in DB. This loops through, in order,
   "SECURITY_USER_IDENTITY_ATTRIBUTES", and first calls the mapper
   function to validate/normalize. Then the db.find_user is called on
   the specified user model attribute.

flask_security.login_user(user, remember=None, authn_via=None)

   Perform the login routine.

   If "SECURITY_TRACKABLE" is used, make sure you commit changes after
   this request (i.e. "app.security.datastore.commit()").

   Parameters:
      * **user** (*User*) -- The user to login

      * **remember** (*bool** | **None*) -- Flag specifying if the
        remember cookie should be set. If "None" use value of
        "SECURITY_DEFAULT_REMEMBER_ME"

      * **authn_via** (*list**[**str**] **| **None*) -- A list of
        strings denoting which mechanism(s) the user authenticated
        with. These should be one or more of ["password", "sms",
        "authenticator", "email"] or other 'auto-login' mechanisms.

   Returns:
      True if user successfully logged in.

   Return type:
      bool

flask_security.logout_user()

   Logs out the current user.

   This will also clean up the remember me cookie if it exists.

   This sends an "identity_changed" signal to note that the current
   identity is now the *AnonymousIdentity*

   Return type:
      None

flask_security.check_and_update_authn_fresh(within, grace, method=None)

   Check if user authenticated within specified time and update grace
   period.

   Parameters:
      * **within** (*timedelta*) -- A timedelta specifying the maximum
        time in the past that the caller authenticated that is still
        considered 'fresh'.

      * **grace** (*timedelta*) -- A timedelta that, if the current
        session is considered 'fresh' will set a grace period for
        which freshness won't be checked. The intent here is that the
        caller shouldn't get part-way though a set of operations and
        suddenly be required to authenticate again.

      * **method** (*str** | **None*) -- Optional - if set and ==
        "basic" then will always return True. (since basic-auth sends
        username/password on every request)

   Return type:
      bool

   If within.total_seconds() is negative, will always return True
   (always 'fresh'). This effectively just disables this entire
   mechanism.

   If "fs_gexp" is in the session and the current timestamp is less
   than that, return True and extend grace time (i.e. set fs_gexp to
   current time + grace).

   If not within the grace period, and within.total_seconds() is 0,
   return False (not fresh).

   Be aware that for this to work, sessions and therefore session
   cookies must be functioning and being sent as part of the request.
   If the required state isn't in the session cookie then return False
   (not 'fresh').

   Warning:

     Be sure the caller is already authenticated PRIOR to calling this
     method.

   Added in version 3.4.0.

   Changed in version 4.0.0: Added *method* parameter.

flask_security.get_hmac(password)

   Returns a Base64 encoded HMAC+SHA512 of the password signed with
   the salt specified by "SECURITY_PASSWORD_SALT".

   Parameters:
      **password** (*str** | **bytes*) -- The password to sign

   Return type:
      bytes

flask_security.get_request_attr(name)

   Retrieve a request local attribute.

   Current public attributes are:

   **fs_authn_via**
      will be set to the authentication mechanism (session, token,
      basic) that the current request was authenticated with.

   Returns None if attribute doesn't exist.

   Added in version 4.0.0.

   Changed in version 4.1.5: Use 'g' rather than request_ctx stack
   which is going away post Flask 2.2

   Parameters:
      **name** (*str*)

   Return type:
      *Any*

flask_security.verify_password(password, password_hash)

   Returns "True" if the password matches the supplied hash.

   Parameters:
      * **password** (*str** | **bytes*) -- A plaintext password to
        verify

      * **password_hash** (*str** | **bytes*) -- The expected hash
        value of the password (usually from your database)

   Return type:
      bool

   Note:

     Make sure that the password passed in has already been
     normalized.

flask_security.verify_and_update_password(password, user)

   Returns "True" if the password is valid for the specified user.

   Additionally, the hashed password in the database is updated if the
   hashing algorithm happens to have changed.

   N.B. you MUST call DB commit if you are using a session-based
   datastore (such as SqlAlchemy) since the user instance might have
   been altered (i.e. "app.security.datastore.commit()"). This is
   usually handled in the view.

   Parameters:
      * **password** (*str** | **bytes*) -- A plaintext password to
        verify

      * **user** (*User*) -- The user to verify against

   Return type:
      bool

   Tip:

     This should not be called directly - rather use
     "UserMixin.verify_and_update_password()"

flask_security.hash_password(password)

   Hash the specified plaintext password.

   Unless the hash algorithm (as specified by
   "SECURITY_PASSWORD_HASH") is listed in the configuration variable
   "SECURITY_PASSWORD_SINGLE_HASH", perform a double hash - first
   create an HMAC from the plaintext password and the value of
   "SECURITY_PASSWORD_SALT", then use the configured hashing
   algorithm. This satisfies OWASP/ASVS section 2.4.5: 'provide
   additional iteration of a key derivation'.

   Added in version 2.0.2.

   Parameters:
      **password** (*str** | **bytes*) -- The plaintext password to
      hash

   Return type:
      str

flask_security.admin_change_password(user, new_passwd, notify=True)

   Administratively change a user's password. Note that this will
   immediately render the user's existing sessions (and possibly
   authentication tokens) invalid.

   It is up to the caller to inform the user of their new password by
   some out-of-band means.

   Parameters:
      * **user** (*User*) -- The user object to change

      * **new_passwd** (*str*) -- The new plain-text password to
        assign to the user.

      * **notify** (*bool*) -- If True and
        "SECURITY_SEND_PASSWORD_CHANGE_EMAIL" is True send the
        'change_notice' email to the user.

   Return type:
      None

flask_security.uia_phone_mapper(identity)

   Used to match identity as a phone number. This is a simple proxy to
   "PhoneUtil"

   See "SECURITY_USER_IDENTITY_ATTRIBUTES".

   Added in version 3.4.0.

   Parameters:
      **identity** (*str*)

   Return type:
      str | None

flask_security.uia_email_mapper(identity)

   Used to match identity as an email.

   Returns:
      Normalized email or None if not valid email.

   Parameters:
      **identity** (*str*)

   Return type:
      str | None

   See "SECURITY_USER_IDENTITY_ATTRIBUTES".

   Added in version 3.4.0.

flask_security.uia_username_mapper(identity)

   Used to match identity as a username. This is a simple proxy to
   "UsernameUtil"

   See "SECURITY_USER_IDENTITY_ATTRIBUTES".

   Added in version 4.1.0.

   Parameters:
      **identity** (*str*)

   Return type:
      str | None

flask_security.url_for_security(endpoint, **values)

   Return a URL for the security blueprint

   Parameters:
      * **endpoint** (*str*) -- the endpoint of the URL (name of the
        function)

      * **values** (*Any*) -- the variable arguments of the URL rule

      * **_external** -- if set to *True*, an absolute URL is
        generated. Server address can be changed via *SERVER_NAME*
        configuration variable which defaults to *localhost*.

      * **_anchor** -- if provided this is added as anchor to the URL.

      * **_method** -- if provided this explicitly specifies an HTTP
        method.

   Return type:
      str

flask_security.send_mail(subject, recipient, template, **context)

   Send an email.

   Parameters:
      * **subject** -- Email subject

      * **recipient** -- Email recipient

      * **template** -- The name of the email template

      * **context** -- The context to render the template with

   This formats the email and passes it off to "MailUtil" to actually
   send the message.

flask_security.check_and_get_token_status(token, serializer_name, within)

   Get the status of a token and return data.

   Parameters:
      * **token** (*str*) -- The token to check

      * **serializer_name** (*str*) -- The name of the serializer. Can
        be one of the following: "confirm", "login", "reset",
        "us_setup" "remember", "two_factor_validity", "wan"

      * **within** (*timedelta*) -- max age - passed as a timedelta

   Returns:
      a tuple of (expired, invalid, data)

   Return type:
      tuple[bool, bool, *Any*]

   Added in version 3.4.0.

flask_security.get_url(endpoint_or_url, qparams=None)

   Returns a URL if a valid endpoint is found. Otherwise, returns the
   provided value.

   Warning:

     If an endpoint ISN'T provided, then it is assumed that the URL is
     external to Flask and if the spa configuration REDIRECT_HOST is
     set will redirect to that host. This could be an issue in
     development.

   Parameters:
      * **endpoint_or_url** (*str*) -- The endpoint name or URL to
        default to

      * **qparams** (*dict**[**str**, **str**] **| **None*) --
        additional query params to add to end of url

   Returns:
      URL

   Return type:
      str

flask_security.password_length_validator(password)

   Test password for length.

   Parameters:
      **password** (*str*) -- Plain text password to check

   Returns:
      "None" if password conforms to length requirements, a list of
      error/suggestions if not.

   Return type:
      list[str] | None

   Added in version 3.4.0.

flask_security.password_complexity_validator(password, is_register, **kwargs)

   Test password for complexity.

   Currently just supports 'zxcvbn'.

   Parameters:
      * **password** (*str*) -- Plain text password to check

      * **is_register** (*bool*) -- if True then kwargs are arbitrary
        additional info. (e.g. info from a registration form). If
        False, must be a SINGLE key "user" that corresponds to the
        current_user. All string values will be extracted and sent to
        the complexity checker.

      * **kwargs** (*Any*)

   Returns:
      "None" if password is complex enough, a list of
      error/suggestions if not. Be aware that zxcvbn does not (easily)
      provide a way to localize messages.

   Return type:
      list[str] | None

   Added in version 3.4.0.

flask_security.password_breached_validator(password)

   Check if password on breached list. Does nothing unless
   "SECURITY_PASSWORD_CHECK_BREACHED" is set. If password is found on
   the breached list, return an error if the count is greater than or
   equal to "SECURITY_PASSWORD_BREACHED_COUNT". Uses "pwned()".

   Parameters:
      **password** (*str*) -- Plain text password to check

   Returns:
      "None" if password passes breached tests, else a list of error
      messages.

   Return type:
      list[str] | None

   Added in version 3.4.0.

flask_security.pwned(password)

   Check password against pwnedpasswords API using k-Anonymity.
   https://haveibeenpwned.com/API/v3

   Returns:
      Count of password in DB (0 means hasn't been compromised)

   Parameters:
      **password** (*str*)

   Return type:
      int

   Can raise HTTPError

   Added in version 3.4.0.

flask_security.unique_identity_attribute(form, field)

   A validator that checks the field data against all configured
   "SECURITY_USER_IDENTITY_ATTRIBUTES". This can be used as part of
   registration.

   Be aware that the "mapper" function likely also normalizes the
   input in addition to validating it.

   Parameters:
      * **form**

      * **field**

   Returns:
      Nothing; if field data corresponds to an existing User,
      ValidationError is raised.

flask_security.us_send_security_token(user, method, totp_secret, phone_number, send_magic_link=False)

   Generate and send the security code.

   Parameters:
      * **user** -- The user to send the code to

      * **method** -- The method in which the code will be sent

      * **totp_secret** -- the unique shared secret of the user

      * **phone_number** -- If 'sms' phone number to send to

      * **send_magic_link** -- If true a magic link that can be
        clicked on will be sent. This shouldn't be sent during a
        setup.

   There is no return value - it is assumed that exceptions are thrown
   by underlying methods that callers can catch.

   Flask-Security code should NOT call this directly - call
   "UserMixin.us_send_security_token()"

   Added in version 3.4.0.

flask_security.tf_send_security_token(user, method, totp_secret, phone_number)

   Sends the security token via email/sms for the specified user.

   Parameters:
      * **user** -- The user to send the code to

      * **method** -- The method in which the code will be sent
        ('email' or 'sms', or 'authenticator') at the moment

      * **totp_secret** -- a unique shared secret of the user

      * **phone_number** -- If 'sms' phone number to send to

   There is no return value - it is assumed that exceptions are thrown
   by underlying methods that callers can catch.

   Flask-Security code should NOT call this directly - call
   "UserMixin.tf_send_security_token()"

class flask_security.AsaList

   SQL-like DBs don't have a List type - so do that here by converting
   to a comma separate string. For SQLAlchemy-based datastores, this
   can be used as:

      Column(MutableList.as_mutable(AsaList()), nullable=True)

class flask_security.SmsSenderBaseClass

   abstract send_sms(from_number, to_number, msg)

      Abstract method for sending sms messages

      Added in version 3.2.0.

      Parameters:
         * **from_number** (*str*)

         * **to_number** (*str*)

         * **msg** (*str*)

      Return type:
         None

class flask_security.SmsSenderFactory

   classmethod createSender(name, *args, **kwargs)

      Initialize an SMS sender.

      Parameters:
         **name** -- Name as registered in SmsSenderFactory:senders
         (e.g. 'Twilio')

      Added in version 3.2.0.

class OauthCbType[oauth: OAuth, token: t.Any]

   This callback is called when the oauth redirect happens. It must
   take the response from the provider and return a tuple of
   <user_model_field_name, value> - which will be used to look up the
   user in the datastore.

class flask_security.OAuthGlue(app, oauthapp=None)

   Provide the necessary glue between the Flask-Security login process
   and authlib oauth client code.

   There are some builtin providers which can be used or not -
   configured via "SECURITY_OAUTH_BUILTIN_PROVIDERS". Any other
   provider can be registered using "register_provider_ext()".

   See Flask OAuth Client

   Added in version 5.1.0.

   Changed in version 5.4.0: Added register_provider_ext which allows
   applications more control to manage new providers (such as extended
   error handling).

   Parameters:
      * **app** (*flask.Flask*)

      * **oauthapp** (*OAuth** | **None*)

   register_provider(name, registration_info, fetch_identity_cb)

      Add a provider to the list.

      Parameters:
         * **name** (*str*) -- Name of provider. This is used as part
           of the "SECURITY_OAUTH_START_URL".

         * **registration_info** (*dict**[**str**, **t.Any**] **|
           **None*) -- Sent directly to authlib. Set this to None if
           you already have registered the provider directly with
           OAuth.

         * **fetch_identity_cb** (*OauthCbType*) -- This callback is
           called when the oauth redirect happens. It must take the
           response from the provider and return a tuple of
           <user_model_field_name, value> - which will be used to look
           up the user in the datastore.

      Return type:
         None

      The provider can be registered with OAuth here or already be
      done by the application. If you register directly with OAuth
      make sure to use the same *name*.

      Deprecated since version 5.4.0: Use "register_provider_ext()"
      instead.

   register_provider_ext(provider)

      Register a provider via an instance of subclass. This is the new
      way - to provide more control for applications

      The authlib provider can be registered here (by calling Oauth)
      or already be done by the application. If you register directly
      with OAuth make sure to use the same *name* when instantiating
      the class.

      Parameters:
         **provider** (*FsOAuthProvider*)

      Return type:
         None

class flask_security.FsOAuthProvider(name, registration_info=None, fetch_identity_cb=None)

   Subclass this or instantiate to add new oauth providers.

   Subclassing allows for customizing additional aspects of the oauth
   flow in particular - a custom error path for oauth flow state
   mismatches and other errors thrown by authlib.

   Call security.oauthglue.register_provider_ext(myproviderclass("myp
   rovider"))

   Parameters:
      * **name** (*str*) -- a name for provider - must match what was
        passed if this is already registered with Oauth.

      * **registration_info** (*dict**[**str**, **t.Any**] **|
        **None*) -- This dict is passed directly to Oauth as part of
        registration - not needed if provider already registered with
        Oauth

      * **fetch_identity_cb** (*OauthCbType** | **None*) -- Call back
        from response to oauth flow.

   authlib_config()

      Return dict with authlib configuration. This is called as part
      of provider registration.

      Return type:
         dict[str, *Any*]

   fetch_identity_cb(oauth, token)

      This callback is called when the oauth redirect happens. It must
      take the response from the provider and return a tuple of
      <user_model_field_name, value> - which will be used to look up
      the user in the datastore.

      Parameters:
         * **oauth** (*OAuth*)

         * **token** (*t.Any*)

      Return type:
         tuple[str, t.Any]

   oauth_response_failure(e)

      Called if authlib authorize_access_token throws an error.

      N.B. flashing doesn't seem to work in some cases - if the
      session cookie has samesite='strict' and it is the first
      registration.

      Parameters:
         **e** (*OAuthError*)

      Return type:
         ResponseValue


Extendable Classes
==================

Each of the following classes can be extended and passed in as part of
Security() instantiation.

class flask_security.PhoneUtil(app)

   Provide parsing and validation for user inputted phone numbers.
   Subclass this to use a different underlying phone number parsing
   library.

   To provide your own implementation, pass in the class as
   "phone_util_cls" at init time. Your class will be instantiated once
   as part of Flask-Security initialization.

   Added in version 3.4.0.

   Changed in version 4.0.0: __init__ takes app argument, and is
   instantiated at Flask-Security initialization time rather than at
   first request.

   Parameters:
      **app** (*flask.Flask*)

   __init__(app)

      Instantiate class.

      Parameters:
         **app** (*flask.Flask*) -- The Flask application being
         initialized.

   get_canonical_form(input_data)

      Validate and return a canonical form to be stored in DB and
      compared against. Returns "None" if input isn't a valid phone
      number.

      Parameters:
         **input_data** (*str*)

      Return type:
         str | None

   validate_phone_number(input_data)

      Return "None" if a valid phone number else the "PHONE_INVALID"
      error message.

      Parameters:
         **input_data** (*str*)

      Return type:
         str | None

class flask_security.MailUtil(app)

   Utility class providing methods for validating, normalizing and
   sending emails.

   This default class uses the email_validator package to handle
   validation and normalization, and the flask_mailman package (if
   initialized) to send emails.

   To provide your own implementation, pass in the class as
   "mail_util_cls" at init time.  Your class will be instantiated once
   as part of app initialization.

   Added in version 4.0.0.

   Parameters:
      **app** (*flask.Flask*)

   __init__(app)

      Instantiate class.

      Parameters:
         **app** (*flask.Flask*) -- The Flask application being
         initialized.

   normalize(email)

      Given an input email - return a normalized version or raise
      EmailValidateException if field value isn't syntactically valid.

      This is called by forms that use email as an identity to be
      looked up.

      Must be called in app context and uses
      "SECURITY_EMAIL_VALIDATOR_ARGS" config variable to pass any
      relevant arguments to email_validator.validate_email() method.

      This defaults to NOT checking for deliverability (i.e. DNS
      checks).

      Parameters:
         **email** (*str*)

      Return type:
         str

   send_mail(template, subject, recipient, sender, body, html, **kwargs)

      Send an email via the Flask-Mailman or Flask-Mail or other mail
      extension.

      Parameters:
         * **template** (*str*) -- the Template name. The message has
           already been rendered however this might be useful to
           differentiate why the email is being sent.

         * **subject** (*str*) -- Email subject

         * **recipient** (*str*) -- Email recipient

         * **sender** (*str** | **tuple*) -- who to send email as (see
           "SECURITY_EMAIL_SENDER")

         * **body** (*str*) -- the rendered body (text)

         * **html** (*str** | **None*) -- the rendered body (html)

         * **kwargs** (*Any*) -- the entire context

      Return type:
         None

      It is possible that sender is a lazy_string for localization
      (unlikely but..) so we cast to str() here to force localization.

   validate(email)

      Validate the given email. If valid, the normalized version is
      returned. This is used by forms/views that require an email that
      likely can have an actual email sent to it.

      Must be called in app context and uses
      "SECURITY_EMAIL_VALIDATOR_ARGS" config variable to pass any
      relevant arguments to email_validator.validate_email() method.

      EmailValidationException is thrown on invalid email.

      Parameters:
         **email** (*str*)

      Return type:
         str

class flask_security.EmailValidateException(message)

   This is raised for any email validation errors. This can be used by
   custom MailUtil implementations to provide custom error messages.

   Parameters:
      **message** (*str*)

class flask_security.PasswordUtil(app)

   Utility class providing methods for validating and normalizing
   passwords.

   To provide your own implementation, pass in the class as
   "password_util_cls" at init time.  Your class will be instantiated
   once as part of app initialization.

   Added in version 4.0.0.

   Parameters:
      **app** (*flask.Flask*)

   __init__(app)

      Instantiate class.

      Parameters:
         **app** (*flask.Flask*) -- The Flask application being
         initialized.

   normalize(password)

      Given an input password - return a normalized version (using
      Python's unicodedata.normalize()). Must be called in app context
      and uses "SECURITY_PASSWORD_NORMALIZE_FORM" config variable.

      Parameters:
         **password** (*str*)

      Return type:
         str

   validate(password, is_register, **kwargs)

      Password validation. Called in app/request context.

      If is_register is True then kwargs will be the contents of the
      register form. If is_register is False, then there is a single
      kwarg "user" which has the current user data model.

      The password is first normalized then validated. Return value is
      a tuple ([msgs], normalized_password)

      Parameters:
         * **password** (*str*)

         * **is_register** (*bool*)

         * **kwargs** (*Any*)

      Return type:
         tuple[list | None, str]

class flask_security.MfRecoveryCodesUtil(app)

   Handle creation, checking, encrypting and decrypting recovery
   codes. Since these are rarely used - keep them encrypted until
   needed - yes if someone gets access to memory they can find the
   key...

   Parameters:
      **app** (*flask.Flask*)

   __init__(app)

      Parameters:
         **app** (*flask.Flask*)

class flask_security.UsernameUtil(app)

   Utility class providing methods for validating and normalizing
   usernames.

   To provide your own implementation, pass in the class as
   "username_util_cls" at init time.  Your class will be instantiated
   once as part of app initialization.

   Added in version 4.1.0.

   Parameters:
      **app** (*flask.Flask*)

   __init__(app)

      Instantiate class.

      Parameters:
         **app** (*flask.Flask*) -- The Flask application being
         initialized.

   check_username(username)

      Given a username - check for allowable character categories.
      This is broken out so applications can easily override this
      method only.

      By default allow letters and numbers (using
      unicodedata.category).

      Returns None if allowed, error message if not allowed.

      Parameters:
         **username** (*str*)

      Return type:
         str | None

   normalize(username)

      Given an input username - return a clean (using bleach) and
      normalized (using Python's unicodedata.normalize()) version.
      Must be called in app context and uses
      "SECURITY_USERNAME_NORMALIZE_FORM" config variable.

      Parameters:
         **username** (*str*)

      Return type:
         str

   validate(username)

      Username validation. Called in app/request context.

      The username is first validated then normalized. Input is
      restricted/validated via a call to check_username. Return value
      is a tuple (msg, normalized_username). msg will be None if
      properly validated.

      It is important that None be returned if data is an empty string
      since otherwise DBs will complain since the field is
      unique/nullable.

      Parameters:
         **username** (*str*)

      Return type:
         tuple[str | None, str | None]

class flask_security.WebauthnUtil(app)

   Utility class allowing an application to fine-tune various Relying
   Party attributes.

   To provide your own implementation, pass in the class as
   "webauthn_util_cls" at init time.  Your class will be instantiated
   once as part of app initialization.

   Added in version 5.0.0.

   Parameters:
      **app** (*flask.Flask*)

   __init__(app)

      Instantiate class.

      Parameters:
         **app** (*flask.Flask*) -- The Flask application being
         initialized.

   authentication_options(user, usage, existing_options)

      Parameters:
         * **user** (*User** | **None*) -- User object - could be used
           to configure on a per-user basis. However, this can be
           null.

         * **usage** (*list**[**str**]*) -- Either "first" or
           "secondary" (webauthn is being used as a second factor for
           authentication)

         * **existing_options** (*dict**[**str**, **t.Any**]*) --
           Currently filled in authentication options.

      Return type:
         dict[str, t.Any]

      Return a dict that will be sent in to
         py-webauthn generate_authentication_options

   authenticator_selection(user, usage)

      Parameters:
         * **user** (*User*) -- User object - could be used to
           configure on a per-user basis.

         * **usage** (*str*) -- Either "first" or "secondary"
           (webauthn is being used as a second factor for
           authentication

      Return type:
         AuthenticatorSelectionCriteria

      Part of the registration ceremony is providing information about
      what kind of authenticators the app is interested in. See:
      https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dictionary-
      authenticatorSelection

      The main options are:
         * whether you want a ResidentKey (discoverable)

         * Attachment - platform or cross-platform

         * Does the key have to provide user-verification

      Note::
         If the key isn't resident then it isn't discoverable which
         means that the user won't be able to use that key unless they
         identify themselves (use the key as a second factor OR type
         in their identity). If they are forced to type in their
         identity PRIOR to being authenticated, then there is the
         possibility that the app will leak username information.

      Parameters:
         * **user** (*User*)

         * **usage** (*str*)

      Return type:
         AuthenticatorSelectionCriteria

   registration_options(user, usage, existing_options)

      Parameters:
         * **user** (*User*) -- User object - could be used to
           configure on a per-user basis.

         * **usage** (*str*) -- Either "first" or "secondary"
           (webauthn is being used as a second factor for
           authentication)

         * **existing_options** (*dict**[**str**, **t.Any**]*) --
           Currently filled in registration options.

      Return type:
         dict[str, t.Any]

      Return a dict that will be sent in to py-webauthn
      generate_registration_options

   user_verification(user, usage)

      As part of signin - do we want/need user verification. This is
      called from /wan-signin and /wan-verify

      Parameters:
         * **user** (*User** | **None*) -- User object - could be used
           to configure on a per-user basis. Note that this may not be
           set on initial wan-signin.

         * **usage** (*list**[**str**]*) -- List of  "first",
           "secondary" (webauthn is being used as a second factor for
           authentication). Note that in the
           "verify"/"reauthentication" case this list is derived from
           "SECURITY_WAN_ALLOW_AS_VERIFY"

      Return type:
         UserVerificationRequirement

class flask_security.Totp(secrets, issuer)

   Encapsulate usage of Passlib TOTP functionality.

   Flask-Security doesn't implement any replay-attack protection out
   of the box as suggested by:
   https://passlib.readthedocs.io/en/stable/narr/totp-tutorial.html
   #match-verify

   Subclass this and implement the get/set last_counter methods. Your
   subclass can be registered at Flask-Security
   creation/initialization time.

   Added in version 3.4.0.

   Parameters:
      * **secrets** (*dict**[**str** | **int**, **str**]*)

      * **issuer** (*str*)

   generate_qrcode(username, totp)

      Generate QRcode
         Using username, totp, generate the actual QRcode image. This
         method can be overridden to fine-tune how the image is
         created - such as size, color etc.

         It must return a string suitable for use in an <img src=xx>
         tag.

      Added in version 4.0.0.

      Parameters:
         * **username** (*str*)

         * **totp** (*str*)

      Return type:
         str

   get_last_counter(user)

      Implement this to fetch stored last_counter from cache.

      Parameters:
         **user** (*User*) -- User model

      Returns:
         last_counter as stored in set_last_counter()

      Return type:
         TotpMatch | None

   set_last_counter(user, tmatch)

      Implement this to cache last_counter.

      Parameters:
         * **user** (*User*) -- User model

         * **tmatch** (*TotpMatch*) -- a TotpMatch as returned from
           totp.verify()

      Return type:
         None


Forms
=====

class flask_security.ChangePasswordForm(*args, **kwargs)

   The default change password form

class flask_security.ConfirmRegisterForm(*args, **kwargs)

   This form is used for registering when 'confirmable' is set. The
   only difference between this and the other RegisterForm is that
   this one doesn't require re-typing in the password...

   We want to support OWASP best-practice around mitigating user
   enumeration. To that end we run through the entire validation
   regardless - this allows us to still return important bad-password
   messages. In the case of an existing email or username - we set
   form.existing_xx so that the view can decide how to match responses
   (e.g. json responses always return 200).

class flask_security.ForgotPasswordForm(*args, **kwargs)

   The default forgot password form

class flask_security.LoginForm(*args, **kwargs)

   The default login form

class flask_security.MfRecoveryCodesForm(*args, **kwargs)

   Generate and fetch recovery codes

class flask_security.MfRecoveryForm(*args, **kwargs)

   Accept recovery code for second factor authentication

class flask_security.PasswordlessLoginForm(*args, **kwargs)

   The passwordless login form

class flask_security.RegisterForm(*args, **kwargs)

class flask_security.ResetPasswordForm(*args, **kwargs)

   The default reset password form

class flask_security.SendConfirmationForm(*args, **kwargs)

   The default send confirmation form

class flask_security.TwoFactorVerifyCodeForm(*args, **kwargs)

   The Two-factor token validation form

class flask_security.TwoFactorSetupForm(*args, **kwargs)

   The Two-factor token validation form

class flask_security.TwoFactorSelectForm(*args, **kwargs)

class flask_security.TwoFactorRescueForm(*args, **kwargs)

   The Two-factor Rescue validation form

class flask_security.UnifiedSigninForm(*args, **kwargs)

   A unified login form For either identity/password or request and
   enter code.

class flask_security.UnifiedSigninSetupForm(*args, **kwargs)

   Setup form

class flask_security.UnifiedSigninSetupValidateForm(*args, **kwargs)

   The unified sign in setup validation form

class flask_security.UnifiedVerifyForm(*args, **kwargs)

   Verify authentication. This is for freshness 'reauthentication'
   required.

class flask_security.VerifyForm(*args, **kwargs)

   The verify authentication form

class flask_security.WebAuthnRegisterForm(*args, **kwargs)

class flask_security.WebAuthnRegisterResponseForm(*args, **kwargs)

class flask_security.WebAuthnSigninForm(*args, **kwargs)

class flask_security.WebAuthnSigninResponseForm(*args, **kwargs)

   This form is used both for signin (primary/first or secondary) and
   verify.

class flask_security.WebAuthnDeleteForm(*args, **kwargs)

class flask_security.WebAuthnVerifyForm(*args, **kwargs)

class flask_security.Form(*args, **kwargs)

class flask_security.FormInfo(instantiator=<function _default_form_instantiator>, cls=None)

   Each view form has a name - assigned by Flask-Security. As part of
   every request, the form is instantiated using (usually)
   request.form or request.json. The default instantiator simply uses
   the class constructor - however applications can provide their OWN
   instantiator which can do pretty much anything as long as it
   returns an instantiated form. The 'cls' argument is optional since
   the instantiator COULD be form specific.

   The instantiator callable will always be called from a flask
   request context and receive the following arguments:

      (name, form_cls_name (optional), **kwargs)

   kwargs will always have *formdata* and often will have *meta*. All
   kwargs must be passed to the underlying form constructor.

   See "flask_security.Security.set_form_info()"

   Added in version 5.1.0.

   Parameters:
      * **instantiator** (*Callable**[**[**...**]**, **Form**]*)

      * **cls** (*Type**[**Form**] **| **None*)


Signals
=======

See the Flask documentation on signals for information on how to use
these signals in your code. All Flask-Security signals are compatible
with Blinker's async implementation. See Blinker async

Tip:

  Remember to add "**extra_args" to your signature so that if we add
  additional parameters in the future your code doesn't break.

See the documentation for the signals provided by the Flask-Login and
Flask-Principal extensions. In addition to those signals, Flask-
Security sends the following signals.

user_authenticated

   Sent when a user successfully authenticates. In addition to the app
   (which is the sender), it is passed *user*, and *authn_via*
   arguments. The *authn_via* argument specifies how the user
   authenticated - it will be a list with possible values of
   "password", "sms", "authenticator", "email", "confirm", "reset",
   "register".

   Added in version 3.4.0.

user_unauthenticated

   Sent when a user fails to authenticate. It is sent from the
   *default_unauthn_handler*. It is passed the app (which is the
   sender).

      Added in version 5.4.0.

user_registered

   Sent when a user registers on the site. In addition to the app
   (which is the sender), it is passed *user*, *confirm_token*
   (deprecated), *confirmation_token* and *form_data* arguments.
   *form_data* is a dictionary representation of registration form's
   content received with the registration request.

user_not_registered

   Sent when a user attempts to register, but is already registered.
   This is ONLY sent when "SECURITY_RETURN_GENERIC_RESPONSES" is
   enabled. It is passed the following arguments:

      * *user* - The existing user model

      * *existing_email* - True if attempting to register an existing
        email

      * *existing_username*- True if attempting to register an
        existing username

      * *form_data* - the entire contents of the posted request form

   Added in version 5.0.0.

user_confirmed

   Sent when a user is confirmed. In addition to the app (which is the
   sender), it is passed a *user* argument.

confirm_instructions_sent

   Sent when a user requests confirmation instructions. In addition to
   the app (which is the sender), it is passed a *user* and
   *confirmation_token* arguments.

login_instructions_sent

   Sent when passwordless login is used and user logs in. In addition
   to the app (which is the sender), it is passed *user* and
   *login_token* arguments.

password_reset

   Sent when a user completes a password reset. In addition to the app
   (which is the sender), it is passed a *user* argument.

password_changed

   Sent when a user completes a password change. In addition to the
   app (which is the sender), it is passed a *user* argument.

reset_password_instructions_sent

   Sent when a user requests a password reset. In addition to the app
   (which is the sender), it is passed *user*, *token* (deprecated),
   and *reset_token* arguments.

tf_code_confirmed

   Sent when a user performs two-factor authentication login on the
   site. In addition to the app (which is the sender), it is passed
   *user* and *method* arguments.

   Added in version 3.3.0.

tf_profile_changed

   Sent when two-factor is used and user logs in. In addition to the
   app (which is the sender), it is passed *user* and *method*
   arguments.

   Added in version 3.3.0.

tf_disabled

   Sent when two-factor is disabled. In addition to the app (which is
   the sender), it is passed *user* argument.

   Added in version 3.3.0.

tf_security_token_sent

   Sent when a two factor security/access code is sent. In addition to
   the app (which is the sender), it is passed *user*, *method*,
   *login_token* and *token* (deprecated) arguments.

   Added in version 3.3.0.

us_security_token_sent

   Sent when a unified sign in access code is sent. In addition to the
   app (which is the sender), it is passed *user*, *method*, *token*
   (deprecated), *login_token*, *phone_number*, and *send_magic_link*
   arguments.

   Added in version 3.4.0.

us_profile_changed

   Sent when user completes changing their unified sign in profile. In
   addition to the app (which is the sender), it is passed *user*,
   *methods*, and *delete* arguments. *delete* will be set to "True"
   if the user removed a sign in option.

   Added in version 3.4.0.

   Changed in version 5.0.0: Added delete argument and changed
   *method* to *methods* which is now a list.

wan_registered

   Sent when a WebAuthn credential was successfully created. In
   addition to the app (which is the sender), it is passed *user* and
   *name* arguments.

   Added in version 5.0.0.

wan_deleted

   Sent when a WebAuthn credential was deleted. In addition to the app
   (which is the sender), it is passed *user* and *name* arguments.

   Added in version 5.0.0.
