_images/logo.png

Strong, Simple, and Precise security for Flask APIs

Overview

API security should be strong, simple, and precise like a Roman Legionary. This package aims to provide that. Using JWT tokens as implemented by PyJWT, flask_praetorian uses a very simple interface to make sure that the users accessing your API’s endpoints are provisioned with the correct roles for access.

This project was heavily influenced by Flask-Security, but intends to supply only essential functionality. Instead of trying to anticipate the needs of all users, flask-praetorian will provide a simple and secure mechanism to provide security for APIs specifically.

This extesion offers a batteries-included approach to security for your API. For essential security concerns for Flask-based APIs, flask-praetorian should supply everything you need.

The flask-praetorian package can be used to:

  • Hash passwords for storing in your database
  • Verify plaintext passwords against the hashed, stored versions
  • Generate authorization tokens upon verification of passwords
  • Check requests to secured endpoints for authorized tokens
  • Supply expiration of tokens and mechanisms for refreshing them
  • Ensure that the users associated with tokens have necessary roles for access
  • Parse user information from request headers or cookies for use in client route handlers
  • Support inclusion of custom user claims in tokens
  • Register new users using email verification

All of this is provided in a very simple to confiure and initialize flask extension. Though simple, the security provided by flask-praetorian is strong due to the usage of the proven security technology of JWT and python’s PassLib package.

Table of Contents

Quickstart

Requirements

  • Python 3.6+

Note on Requirements

I do not currently plan to support older versions of python. Python 2 support is very unlikely to arrive as the original author is a die-hard believer in python 3. As for older versions of python 3, my test harnesses depend on some features only available in python 3.4 and up.

Installation

Note

flask-praetorian does not support distutils or setuptools because the author has very strong feelings about python packaging and the role pip plays in taking us into a bright new future of standardized and usable python packaging

Install from pypi

This will install the latest release of flask-praetorian from pypi via pip:

$ pip install flask-praetorian

Install latest version from github

If you would like a version other than the latest published on pypi, you may do so by cloning the git repository:

$ git clone https://github.com/dusktreader/flask-praetorian.git

Next, checkout the branch or tag that you wish to use:

$ cd flask-praetorian
$ git checkout integration

Finally, use poetry to install from the local directory:

$ poetry install

Example

A minimal example of how to use the flask-praetorian decorators is included:

import flask
import tempfile
import flask_sqlalchemy
import flask_praetorian
import flask_cors

db = flask_sqlalchemy.SQLAlchemy()
guard = flask_praetorian.Praetorian()
cors = flask_cors.CORS()


# A generic user model that might be used by an app powered by flask-praetorian
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.Text, unique=True)
    hashed_password = db.Column(db.Text)
    roles = db.Column(db.Text)
    is_active = db.Column(db.Boolean, default=True, server_default="true")

    @property
    def identity(self):
        """
        *Required Attribute or Property*

        flask-praetorian requires that the user class has an ``identity`` instance
        attribute or property that provides the unique id of the user instance
        """
        return self.id

    @property
    def rolenames(self):
        """
        *Required Attribute or Property*

        flask-praetorian requires that the user class has a ``rolenames`` instance
        attribute or property that provides a list of strings that describe the roles
        attached to the user instance
        """
        try:
            return self.roles.split(",")
        except Exception:
            return []

    @property
    def password(self):
        """
        *Required Attribute or Property*

        flask-praetorian requires that the user class has a ``password`` instance
        attribute or property that provides the hashed password assigned to the user
        instance
        """
        return self.hashed_password

    @classmethod
    def lookup(cls, username):
        """
        *Required Method*

        flask-praetorian requires that the user class implements a ``lookup()``
        class method that takes a single ``username`` argument and returns a user
        instance if there is one that matches or ``None`` if there is not.
        """
        return cls.query.filter_by(username=username).one_or_none()

    @classmethod
    def identify(cls, id):
        """
        *Required Method*

        flask-praetorian requires that the user class implements an ``identify()``
        class method that takes a single ``id`` argument and returns user instance if
        there is one that matches or ``None`` if there is not.
        """
        return cls.query.get(id)

    def is_valid(self):
        return self.is_active


# Initialize flask app for the example
app = flask.Flask(__name__)
app.debug = True
app.config["SECRET_KEY"] = "top secret"
app.config["JWT_ACCESS_LIFESPAN"] = {"hours": 24}
app.config["JWT_REFRESH_LIFESPAN"] = {"days": 30}

# Initialize the flask-praetorian instance for the app
guard.init_app(app, User)

# Initialize a local database for the example
local_database = tempfile.NamedTemporaryFile(prefix="local", suffix=".db")
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///{}".format(local_database)
db.init_app(app)

# Initializes CORS so that the api_tool can talk to the example app
cors.init_app(app)

# Add users for the example
with app.app_context():
    db.create_all()
    db.session.add(
        User(
            username="TheDude",
            password=guard.hash_password("abides"),
        )
    )
    db.session.add(
        User(
            username="Walter",
            password=guard.hash_password("calmerthanyouare"),
            roles="admin",
        )
    )
    db.session.add(
        User(
            username="Donnie",
            password=guard.hash_password("iamthewalrus"),
            roles="operator",
        )
    )
    db.session.add(
        User(
            username="Maude",
            password=guard.hash_password("andthorough"),
            roles="operator,admin",
        )
    )
    db.session.commit()


# Set up some routes for the example


@app.route("/login", methods=["POST"])
def login():
    """
    Logs a user in by parsing a POST request containing user credentials and
    issuing a JWT token.
    .. example::
       $ curl http://localhost:5000/login -X POST \
         -d '{"username":"Walter","password":"calmerthanyouare"}'
    """
    req = flask.request.get_json(force=True)
    username = req.get("username", None)
    password = req.get("password", None)
    user = guard.authenticate(username, password)
    ret = {"access_token": guard.encode_jwt_token(user)}
    return (flask.jsonify(ret), 200)


@app.route("/protected")
@flask_praetorian.auth_required
def protected():
    """
    A protected endpoint. The auth_required decorator will require a header
    containing a valid JWT
    .. example::
       $ curl http://localhost:5000/protected -X GET \
         -H "Authorization: Bearer <your_token>"
    """
    return flask.jsonify(
        message="protected endpoint (allowed user {})".format(
            flask_praetorian.current_user().username,
        )
    )


@app.route("/protected_admin_required")
@flask_praetorian.roles_required("admin")
def protected_admin_required():
    """
    A protected endpoint that requires a role. The roles_required decorator
    will require that the supplied JWT includes the required roles
    .. example::
       $ curl http://localhost:5000/protected_admin_required -X GET \
          -H "Authorization: Bearer <your_token>"
    """
    return flask.jsonify(
        message="protected_admin_required endpoint (allowed user {})".format(
            flask_praetorian.current_user().username,
        )
    )


@app.route("/protected_operator_accepted")
@flask_praetorian.roles_accepted("operator", "admin")
def protected_operator_accepted():
    """
    A protected endpoint that accepts any of the listed roles. The
    roles_accepted decorator will require that the supplied JWT includes at
    least one of the accepted roles
    .. example::
       $ curl http://localhost/protected_operator_accepted -X GET \
         -H "Authorization: Bearer <your_token>"
    """
    return flask.jsonify(
        message="protected_operator_accepted endpoint (allowed usr {})".format(
            flask_praetorian.current_user().username,
        )
    )


# Run the example
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

The above code can be found in example/basic.py.

Notes

Refreshing Tokens

One of the keys to proper security with auth tokens is to make sure that they only last a finite amont of time. This makes sure that if the token is stolen, it cannot be used in perpetuity to gain complete access to the user. However, calls to the database to validate a user on every http request would dramatically slow down an application.

To mitigate both situations, the concept of token refreshing has been introduced. The idea is that the user is re-checked periodically, but not on every request. After some fixed amount of time, the database is re-checked to make sure that a user is still allowed access.

At that point in time, a new token is issued with the same claims as the first except its refresh lifespan is not extened. This is so that a token cannot be refreshed in perpetuity.

Once a token’s access lifespan and refresh lifespan are both expired, the user must log in again.

Rate Limiting

There is not any sort of rate-limiting protection offered by flask-praetorian. Thus, if your app does not implment such a thing, it could be vulnerable to brute force attacks. It’s advisable that you implement some sort of system for limiting incorrect username/password attempts.

Error Handling

By default, flask-praetorian will add an error handler to Flask for PraetorianErrors. This error handler produces nicely formatted json responses with status codes that reflect the failures. The flask-praetorian package’s custom exception type PraetorianError derives from the FlaskBuzz base exception type from the flask-buzz exceptions package. The flask-buzz package provides convenience methods for error handlers.

The error handling may be disabled by adding a configuration setting for DISABLE_PRAETORIAN_ERROR_HANDLER. You may wish to do this if you want to customize your error handling even further.

For example, you may wish to have the error handler log messages about failures prior to returning an error response. In this case, you can still take advantage of flask-buzz’s features to do so:

app.register_error_handler(
    PraetorianError,
    PraetorianError.build_error_handler(lambda e: logger.error(e.message)),
)

Flask-Restplus compatibility

Flask-Restplus’s error handler is not compatible with the normal Flask error handler. What’s more, prior to Flask-Restplus 0.11.0, Flask-Restplus’s error handler did not automatically handle derived exception classes, so you would need to handle each and every PraetorianError type in your handler.

The flask-buzz exceptions package provides a helper method for registering error handlers with flask-restplus:

PraetorianError.register_error_handler_with_flask_restplus(api)

Like the normal Flask error handler, additional tasks may be passed to this method to be executed on the error prior to returning the response

Configuration Settings

Requirements for the user_class

The user_class argument supplied during initialization represents the class that should be used to check for authorization for decorated routes. The class itself may be implemented in any way that you see fit. It must, however, satisfy the following requirements:

  • Provide a lookup class method that:
    • should take a single argument of the name of the user
    • should return an instance of the user_class or None
  • Provide an identify class method
    • should take a single argument of the unique id of the user
    • should return an instance of the user_class or None
  • Provide a rolenames instance attribute
    • only applies if roles are not disabled. See PRAETORIAN_ROLES_DISABLED setting
    • should return a list of string roles assigned to the user
  • Provide a password instance attribute
    • should return the hashed password assigned to the user
  • Provide an identity instance attribute
    • should return the unique id of the user

Although the example given in the documentation uses a SQLAlchemy model for the userclass, this is not a requirement.

flask-praetorian comparison to other libraries

The flask-praetorian extension doesn’t really offer functionality that isn’t covered by other packages or a combination of others. However, it serves a very targeted purpose and is intended to be a batteries-included solution for API security that’s ready to go out-of-the-box.

This section will discuss how flask-praetorian differs from the others and what sort of advantages it provides

Other similar security packages include:

* flask-jwt
* flask-jwt-extended
* flask-jwt-simple
* flask-security

flask-jwt

The flask-jwt extension was one of the original jwt based flask security extensions. It was a mostly fully featured securtiy package, and it was highly opinionated. This was the package that the precursor to flask-praetorian sought to use. However functionality was limited, and while a solution to one particular issue was being pursued, it became apparent that flask-jwt had been abandoned.

The last commit on this package was 4 years ago (as of this writing), and the repository has 36 outstanding issues and 30 outstanding pull-requests. The flask-jwt extension should probably not be chosen for this reason alone as it will not be updated going forward.

Password authentication is supported as a stubbed out method to allow client app to easily connect it, but the verification is not implemented at all.

There is a route protection decorator in @jwt_required, but no further refinement of access control is offered.

The flask-praetorian extension offers all of these features and more.

flask-jwt-extended

After the maintainer of flask-jwt stopped updating his package, flask-jwt-extended was started as a new project. The author originally wanted to extend flask-jwt but instead had to create a new project. Like flask-jwt, flask-jwt-extended is opinionated, but takes things to the next level. The flask-jwt-exetended extension is very full featured and eminently configurable. It is an excellent package with a lot of activity and support.

The flask-jwt-extended package supports the following features that are not found in flask-praetorian:

* Using cookies for JWT storage
* Partial route protection
* Requiring fresh tokens
* Custom placement of JWT in HTTP requests (headers, body, etc)
* CSRF protection

However, flask-jwt-extended does not include some nice features of flask-praetorian such as password hashing, password verification, role based access, email registration and verification. Additionally, the API for flask-praetorian is simpler and there is less configuration.

The flask-praetorian package aims to be a complete security extension while flask-jwt-extended focuses on JWT-based auth and supporting many patterns of access.

Additionally, flask-praetorian aims to be simpler to configure and support specific and common access patters for APIs using JWT.

flask-jwt-simple

The flask-jwt-simple extension is meant to be a bare-bones extension that adds JWT auth to flask. I has few features outside of a decorator that requires JWT auth and methods to produce JWTs.

It is useful for rapid prototyping or building out your own JWT based security for your app.

However, it’s feature set is extremely limited compared to flask-praetorian.

flask-security

This package was the original inspiration for flask-praetorian. It is a fully- featured security extension for flask and offers some of the same features as flask-praetorian like password verification, role based access, and others. However, this extension is meant to be used for flask websites and includes wtform components and other things that are not neeeded for flask-based APIs. Including all the extra stuff is both cumbersome and unnecessary in an API. The flask-praetorian extension intends to be a similar batteries-included package while offering a simple API with a full set of security tools.

flask-praetorian Developer Guide

This developer guide will help you get started on working on flask-praetorian in a development environment so that you can add features and run tests

Dependencies

  • python3
  • poetry

Setup

This package relies on Poetry for dependency management and packaging.

Install the package for development

In order to install the package for development and to include all its dependencies, navigate to the root project folder and execute this command:

$ poetry install

The full list of dependencies can be found in pyproject.toml

Running tests

This project uses pytest for its unit testing.

Tests are executed by invoking pytest through poetry from the root of the project:

$ poetry run pytest -ra tests

The -ra option is recommended as it will report skipped tests

Documentation

readthedocs.org

Documentation for the flask-praetorian package is available on readthedocs.org. It is configured so that new documentation is generated from the flask-praetorian docs directory automatically whenever a new commit is pushed to the master branch. So, developers need not do anything to build documentation.

Adding further documentation

The majority of the automatically generated developer’s guide is produced from python docstrings

This project uses the sphinx extension sphinx-apidoc to generate help pages from the docstrings at the module, class, and function level.

There are several special keywords that can be added to docstrings that have special significance for sphinx. The most useful of these are the :param: and :return: keywords.

Items can be added to the project-wide todo list and notes that is shown in the /help endpoint

Here is an example method with marked up docstring:

def some_method(param1, param2):
    """
    This is a method that does stuff

    :param: param1: This is the first param
    :param: param2: This is the second param
    :return: A string that says 'yo'
    .. todo:: Make this method more awesomer
    .. note:: This is just a lame example
    """
    return 'yo'

Code Style

This project uses the style constraints described in pep8

Please follow the style guide as stated. Also, please enforce the style guide during code reviews.

Useful tools

sphinx-view

reStructuredText documents and sphinx documentation can be previewed as they are edited on your workstation using a tool called sphinx-view. It is indispensable when updating this README.rst document or one of the templates for the autognerated sphinx documentation.

flake8

The flake8 tool is very useful for checking for compliant code style. Flake8 is included when flask-praetorian is installed with poetry.

The flake8 tool is invoked by targeting a specific source directory:

$ poetry run flake8 flask_praetorian

Particular directories and source files may also be targeted directly

vim Editor plugin

The vim-flake8 plugin for vim is very useful for identifying style issues inside the vim editor. the vim-flake8 plugin is most easily added by using pathogen.

The following vim binding is useful to execute the flake8 check on write for all python source files:

# autocmd BufWritePost *.py call Flake8()

It is most useful to include that in your .vimrc file

Other notes

  • flask-praetorian uses the pendulum to timestamp its JWT tokens with UTC timestamps

Contributing Guidelines

Security Concerns

Before any further discussion, a point about security needs to be addressed. If you find a serious security vulnerability that could affect current users, please report it to maintainers via email or some form of private communication. For other issue reports, see below.

Thanks!

First, thank you for your interest in contributing to flask-praetorian! Even though this is a small flask-extension project, it takes a bit of work to keep it maintained. All contributions help and improve the extension.

Contact Us

The maintainers of flask-praetorian can be reached most easily via email:

* Tucker Beck <tucker.beck@gmail.com>

Conduct

Everyone’s conduct should be respectful and friendly. For most folks, these things don’t need to be spelled out. However, to establish a baseline of acceptable conduct, the flask-praetorian project expects contributors to adhere to a customized version of the Python Software Foundation’s Code of Conduct. Please see the “Conduct” section to reference the code of conduct. Any issues working with other contributors should be reported to the maintainers

Contribution Recommendations

Github Issues

The first and primary source of contributions is opening issues on github. Please feel free to open issues when you find problems or wish to request a feature. All issues will be treated seriously and taken under consideration. However, the maintainers may disregard/close issues at their discretion.

Issues are most helpful when they contain specifics about the problem they address. Specific error messages, references to specific lines of code, environment contexts, and such are extremely helpful.

Code Contributions

Code contributions should be submitted via pull-requests on github. Project maintainers will review pull-requests and may test new features out. All merge requests should come with commit messages that describe the changes as well as a reference to the issue that the code addresses.

All commits should include the issue #

Commit messages should follow this format:

Issue #56: Fixed gizmo component that was parfolecting

The parfolection happening in the gizmo component was causing a vulterability
in the anti-parfolection checks during the enmurculation process.

This was addressed by caching the restults of parfolection prior to
enmurculation.

Also:
* Added and updated unit tests
* Added documentation
* Cleaned up some code

Code contributions should follow best-practices where possible. Use the Zen of Python as a guideline. All code must stick to pep8 style guidelines.

Adding addtional dependencies should be limited except where needed functionality can be easily added through pip packages. Please include dependencies that are only applicable to development and testing in the dev dependency list. Packages should only be added to the dependency lists if:

* They are actively maintained
* They are widely used
* They are hosted on pypi.org
* They have source code hosted on a public repository (github, gitlab, bitbucket, etc)
* They include tests in their repositories
* They include a software license

Documentation

Help with documentation is always welcome.

The flask-praetorian project uses sphinx for document generation.

Documentation lives in the docs subdirectory. Added pages should be referenced from the table of contents.

Documentation should be clear, include examples where possible, and reference source material as much as possible.

Documentation through code comments should be kept to a minimum. Code should be as self-documenting as possible. If a section of code needs some explanation, the bulk of it should be be presented as sphix-compatible docstrings for methods, modules, and classes.

Non-preferred Contributions

There are some types of contribution that aren’t as helpful and are not as welcome:

* Complaints without suggestion
* Criticism about the overall approach of the extension
* Copied code without attribution
* Promotion of personal packages/projects without due need
* Sarcasm/ridicule of contributions or design choices

Code of Conduct

Welcome

Contributors and users of flask-praetorian come from folks from around the globe with a diverse set of skills, personalities, and experiences. It is through these differences that our community experiences great successes and continued growth. When you’re working with other contributors or users, we expect you to follow these guidelines which help steer our interactions and strive to keep the development of flask-praetorian positive, successful, and growing.

Be Open

Contributors to flask-praetorian are expected to be open. They should be open to collaboration, whether it’s on issues, pull-requests, or otherwise. We’re receptive to constructive comment and criticism, as the experiences and skill sets of other members contribute to the whole of our efforts. We’re accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference.

Be Considerate

Contributors to flask-praetorian are expected to be considerate of their peers. We’re thoughtful when addressing the efforts of others, keeping in mind that often times the labor was completed simply for the good of the community. We’re attentive in our communications, whether in person or online, and we’re tactful when approaching differing views.

Be Respectful

Contributors to flask-praetorian are expected to be respectful. We’re respectful of others, their positions, their skills, their commitments, and their efforts. We’re respectful of competing packages and others in the Flask and Python community at large. We’re respectful of the processes set forth in the Python community, and we work within them. When we disagree, we are courteous in raising our issues.

Conclusion

Overall, we’re good to each other. Contribution is done on a voluntary basis, and folks are expected to be good and decent in their conduct. Any disputes will be resolved by the maintainers and those that do not wish to follow the guidelines will be asked to stop contributing.

flask_praetorian package

Submodules

flask_praetorian.base module

class flask_praetorian.base.Praetorian(app=None, user_class=None, is_blacklisted=None, encode_jwt_token_hook=None, refresh_jwt_token_hook=None)

Bases: object

Comprises the implementation for the flask-praetorian flask extension. Provides a tool that allows password authentication and token provision for applications and designated endpoints

authenticate(username, password)

Verifies that a password matches the stored password for that username. If verification passes, the matching user instance is returned

encode_eternal_jwt_token(user, **custom_claims)

This utility function encodes a jwt token that never expires

Note

This should be used sparingly since the token could become a security concern if it is ever lost. If you use this method, you should be sure that your application also implements a blacklist so that a given token can be blocked should it be lost or become a security concern

encode_jwt_token(user, override_access_lifespan=None, override_refresh_lifespan=None, bypass_user_check=False, is_registration_token=False, is_reset_token=False, **custom_claims)

Encodes user data into a jwt token that can be used for authorization at protected endpoints

Param:override_access_lifespan: Override’s the instance’s access lifespan to set a custom duration after which the new token’s accessability will expire. May not exceed the refresh_lifespan
Param:override_refresh_lifespan: Override’s the instance’s refresh lifespan to set a custom duration after which the new token’s refreshability will expire.
Param:bypass_user_check: Override checking the user for being real/active. Used for registration token generation.
Param:is_registration_token: Indicates that the token will be used only for email-based registration
Param:custom_claims: Additional claims that should be packed in the payload. Note that any claims supplied here must be JSON compatible types
encrypt_password(raw_password)
NOTE This should be deprecated as its an incorrect definition for
what is actually being done – we are hashing, not encrypting
error_handler(error)

Provides a flask error handler that is used for PraetorianErrors (and derived exceptions).

extract_jwt_token(token, access_type=<AccessType.access: 'ACCESS'>)

Extracts a data dictionary from a jwt token

get_user_from_registration_token(token)

Gets a user based on the registration token that is supplied. Verifies that the token is a regisration token and that the user can be properly retrieved

hash_password(raw_password)

Hashes a plaintext password using the stored passlib password context

init_app(app=None, user_class=None, is_blacklisted=None, encode_jwt_token_hook=None, refresh_jwt_token_hook=None)

Initializes the Praetorian extension

Param:

app: The flask app to bind this extension to

Param:

user_class: The class used to interact with user data

Param:

is_blacklisted: A method that may optionally be used to check the token against a blacklist when access or refresh is requested should take the jti for the token to check as a single argument. Returns True if the jti is blacklisted, False otherwise. By default, always returns False.

Parameters:
  • encode_jwt_token_hook – A method that may optionally be called right before an encoded jwt is generated. Should take payload_parts which contains the ingredients for the jwt.
  • refresh_jwt_token_hook – A method that may optionally be called right before an encoded jwt is refreshed. Should take payload_parts which contains the ingredients for the jwt.
pack_header_for_user(user, override_access_lifespan=None, override_refresh_lifespan=None, **custom_claims)

Encodes a jwt token and packages it into a header dict for a given user

Param:user: The user to package the header for
Param:override_access_lifespan: Override’s the instance’s access lifespan to set a custom duration after which the new token’s accessability will expire. May not exceed the refresh_lifespan
Param:override_refresh_lifespan: Override’s the instance’s refresh lifespan to set a custom duration after which the new token’s refreshability will expire.
Param:custom_claims: Additional claims that should be packed in the payload. Note that any claims supplied here must be JSON compatible types
read_token()

Unpacks a jwt token from the current flask request

read_token_from_header()

Unpacks a jwt token from the current flask request

refresh_jwt_token(token, override_access_lifespan=None)

Creates a new token for a user if and only if the old token’s access permission is expired but its refresh permission is not yet expired. The new token’s refresh expiration moment is the same as the old token’s, but the new token’s access expiration is refreshed

Param:token: The existing jwt token that needs to be replaced with a new, refreshed token
Param:override_access_lifespan: Override’s the instance’s access lifespan to set a custom duration after which the new token’s accessability will expire. May not exceed the refresh lifespan
send_registration_email(email, user=None, template=None, confirmation_sender=None, confirmation_uri=None, subject=None, override_access_lifespan=None)
Sends a registration email to a new user, containing a time expiring
token usable for validation. This requires your application is initialized with a mail extension, which supports Flask-Mail’s Message() object and a send() method.
Returns a dict containing the information sent, along with the
result from mail send.
Param:user: The user object to tie claim to (username, id, email, etc)
Param:template: HTML Template for confirmation email. If not provided, a stock entry is used
Param:confirmation_sender: The sender that shoudl be attached to the confirmation email. Overrides the PRAETORIAN_CONFIRMRATION_SENDER config setting
Param:confirmation_uri: The uri that should be visited to complete email registration. Should usually be a uri to a frontend or external service that calls a ‘finalize’ method in the api to complete registration. Will override the PRAETORIAN_CONFIRMATION_URI config setting
Param:subject: The registration email subject. Will override the PRAETORIAN_CONFIRMATION_SUBJECT config setting.
Param:override_access_lifespan: Overrides the JWT_ACCESS_LIFESPAN to set an access lifespan for the registration token.
send_reset_email(email, template=None, reset_sender=None, reset_uri=None, subject=None, override_access_lifespan=None)
Sends a password reset email to a user, containing a time expiring
token usable for validation. This requires your application is initialized with a mail extension, which supports Flask-Mail’s Message() object and a send() method.
Returns a dict containing the information sent, along with the
result from mail send.
Param:email: The email address to attempt to send to
Param:template: HTML Template for reset email. If not provided, a stock entry is used
Param:confirmation_sender: The sender that shoudl be attached to the reset email. Overrides the PRAETORIAN_RESET_SENDER config setting
Param:confirmation_uri: The uri that should be visited to complete password reset. Should usually be a uri to a frontend or external service that calls the ‘validate_reset_token()’ method in the api to complete reset. Will override the PRAETORIAN_RESET_URI config setting
Param:subject: The reset email subject. Will override the PRAETORIAN_RESET_SUBJECT config setting.
Param:override_access_lifespan: Overrides the JWT_ACCESS_LIFESPAN to set an access lifespan for the registration token.
send_token_email(email, user=None, template=None, action_sender=None, action_uri=None, subject=None, override_access_lifespan=None, custom_token=None)
Sends an email to a user, containing a time expiring
token usable for several actions. This requires your application is initialized with a mail extension, which supports Flask-Mail’s Message() object and a send() method.
Returns a dict containing the information sent, along with the
result from mail send.
Param:email: The email address to use (username, id, email, etc)
Param:user: The user object to tie claim to (username, id, email, etc)
Param:template: HTML Template for confirmation email. If not provided, a stock entry is used
Param:action_sender: The sender that should be attached to the confirmation email.
Param:action_uri: The uri that should be visited to complete the token action.
Param:subject: The email subject.
Param:override_access_lifespan: Overrides the JWT_ACCESS_LIFESPAN to set an access lifespan for the registration token.
Param:custom_token: The token to be carried as the email’s payload
validate_reset_token(token)

Validates a password reset request based on the reset token that is supplied. Verifies that the token is a reset token and that the user can be properly retrieved

verify_and_update(user=None, password=None)
Validate a password hash contained in the user object is
hashed with the defined hash scheme (PRAETORIAN_HASH_SCHEME).
If not, raise an Exception of LegacySchema, unless the
password arguement is provided, in which case an attempt to call user.save() will be made, updating the hashed password to the currently desired hash scheme (PRAETORIAN_HASH_SCHEME).
Param:

user: The user object to tie claim to (username, id, email, etc). MUST include the hashed password field, defined as user.password

Param:

password: The user’s provide password from login. If present, this is used to validate

and then attempt to update with the new PRAETORIAN_HASH_SCHEME scheme.

flask_praetorian.decorators module

flask_praetorian.decorators.auth_accepted(method)

This decorator is used to allow an authenticated user to be identified while being able to access a flask route, and adds the current user to the current flask context.

flask_praetorian.decorators.auth_required(method)

This decorator is used to ensure that a user is authenticated before being able to access a flask route. It also adds the current user to the current flask context.

flask_praetorian.decorators.roles_accepted(*accepted_rolenames)

This decorator ensures that any uses accessing the decorated route have one of the needed roles to access it. If an @auth_required decorator is not supplied already, this decorator will implicitly check @auth_required first

flask_praetorian.decorators.roles_required(*required_rolenames)

This decorator ensures that any uses accessing the decorated route have all the needed roles to access it. If an @auth_required decorator is not supplied already, this decorator will implicitly check @auth_required first

flask_praetorian.exceptions module

exception flask_praetorian.exceptions.AuthenticationError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The entered user’s password did not match the stored password

exception flask_praetorian.exceptions.BlacklistedError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The jwt token has been blacklisted and may not be used any more

status_code = 403
exception flask_praetorian.exceptions.ClaimCollisionError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

” Custom claims to pack into the JWT payload collide with reserved claims

exception flask_praetorian.exceptions.ConfigurationError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

There was a problem with the configuration

exception flask_praetorian.exceptions.EarlyRefreshError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The jwt token has not yet expired for access and may not be refreshed

status_code = 425
exception flask_praetorian.exceptions.ExpiredAccessError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The jwt token has expired for access and must be refreshed

exception flask_praetorian.exceptions.ExpiredRefreshError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The jwt token has expired for refresh. An entirely new token must be issued

exception flask_praetorian.exceptions.InvalidRegistrationToken(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The supplied registration token is invalid

exception flask_praetorian.exceptions.InvalidResetToken(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The supplied registration token is invalid

exception flask_praetorian.exceptions.InvalidTokenHeader(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The token contained in the header is invalid

exception flask_praetorian.exceptions.InvalidUserError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The user is no longer valid and is now not authorized

status_code = 403
exception flask_praetorian.exceptions.LegacyScheme(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The processed hash is using an outdated scheme

exception flask_praetorian.exceptions.MissingClaimError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The jwt token is missing a required claim

exception flask_praetorian.exceptions.MissingRoleError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The token is missing a required role

status_code = 403
exception flask_praetorian.exceptions.MissingToken(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The header is missing the required jwt token

exception flask_praetorian.exceptions.MissingUserError(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

The user could not be identified

exception flask_praetorian.exceptions.MisusedRegistrationToken(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

Attempted to use a registration token for normal access

exception flask_praetorian.exceptions.MisusedResetToken(message, *format_args, **format_kwds)

Bases: flask_praetorian.exceptions.PraetorianError

Attempted to use a password reset token for normal access

exception flask_praetorian.exceptions.PraetorianError(message, *format_args, **format_kwds)

Bases: flask_buzz.FlaskBuzz

Provides a custom exception class for flask-praetorian based on flask-buzz. flask-buzz on gitub

status_code = 401