
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.4, 3.5, 3.6, or 3.7
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)
password = db.Column(db.Text)
roles = db.Column(db.Text)
is_active = db.Column(db.Boolean, default=True, server_default='true')
@property
def rolenames(self):
try:
return self.roles.split(',')
except Exception:
return []
@classmethod
def lookup(cls, username):
return cls.query.filter_by(username=username).one_or_none()
@classmethod
def identify(cls, id):
return cls.query.get(id)
@property
def identity(self):
return self.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¶
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¶
Flag | Description | Default Value |
---|---|---|
SECRET_KEY |
A secret string value used to salt encryptions and hashes for the app. ABSOLUTELY MUST BE SET TO SOMETHING OTHER THAN DEFAULT IN PRODUCTION. |
DO NOT USE THE DEFAULT IN PRODUCTION |
PRAETORIAN_HASH_SCHEME |
The hash scheme used to hash passwords in the database. If unset,
passlib will use the default scheme which is pbkdf2_sha512 |
'pbkdf2_sha512' |
JWT_ALLOWED_ALGORITHMS |
A list of allowed algorithms that may be used to hash the JWT. See the PyJWT docs for more details. | ['HS256'] |
JWT_ALGORITHM |
The jwt hashing algorithm to be used to encode tokens | 'HS256' |
JWT_ACCESS_LIFESPAN |
The default length of time that a JWT may be used to access a protected endpoint. See the PyJWT docs for more details. | {'minutes': 15} |
JWT_REFRESH_LIFESPAN |
The default length of time that a JWT may be refreshed. JWT may also not be refreshed if its access lifespan is not expired. | {'days': 30} |
JWT_PLACES |
A list of places where JWT will be checked | ['header', 'cookie'] |
JWT_COOKIE_NAME |
The name of the cookie in HTTP requests where the JWT will be found | 'access_token' |
JWT_HEADER_NAME |
The name of the header in HTTP requests where the JWT will be found | 'Authorization' |
JWT_HEADER_TYPE |
A string describing the type of the header. Usually ‘Bearer’ but may be customized by the user | 'Bearer' |
USER_CLASS_VALIDATION_METHOD |
The name of the method on a user instance that should be used to validate that the user is active in the system. | 'is_valid' |
DISABLE_PRAETORIAN_ERROR_HANDLER |
Do not register the flask error handler automatically. The user may wish to configure the error handler themselves | None |
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
orNone
- 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
orNone
- Provide a
rolenames
instance attribute- 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.
Tutorial¶
The tutorial for flask-praetorian has been moved into its own project:
`tutorial github repo <https://github.com/dusktreader/flask-praetorian-tutorial`_ `tutorial readthedocs <https://flask-praetorian-tutorial.readthedocs.io/en/latest/`_
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¶
flask_praetorian init
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, sender='no-reply@praetorian')¶ - 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.
-
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_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¶
-