Strong, Simple, and Precise security for Flask APIs (using jwt)

Overview
Latest Published Version Build Status Documentation Build Status

flask-praetorian

Strong, Simple, and Precise security for Flask APIs

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 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 configure 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.

Super-quick Start

  • requirements: python versions 3.4, 3.5, 3.6, and 3.7
  • install through pip: $ pip install flask-praetorian
  • minimal usage example: example/basic.py

Documentation

The complete documentation can be found at the flask-praetorian home page

Comments
  • PraetorianError is not caught resulting in 500 error

    PraetorianError is not caught resulting in 500 error

    I'm using flask_restplus which kinda looks like the best choice to go with flask_praetorian (or in reverse order), and @api.errorhandler does not catch PraetorianError. But it does catch it's children, InvalidToken, InvalidUser etc.

    ~I'm wondering, is it possible to change exception class via config or maybe provide more usable for Flask exception instead of one making server go 500?~

    ~I'm also kinda new to Flask, so maybe exception thrown when JWT not found is ok and I just need to turn some switch on in Flask so it will handle it gracefully?~

    ~Thanks!~

    ~edit: actually, no JWT and decoding JWT errors may be more like... NotAuthrozired error or something?~

    opened by idchlife 7
  • Issue #250: allow flask 2.0, bump to version 1.2.1

    Issue #250: allow flask 2.0, bump to version 1.2.1

    pytest didn't have any complaints and I didn't face any complications when testing it with my project. I suggest to just update the dependencies.

    fixes #250

    opened by jvllmr 6
  • Add permissions to flask-praetorian

    Add permissions to flask-praetorian

    Sometimes users need more fine-grained control over access to users of the same class (role). For this, we should support a set of permissions.

    This should be a completely optional feature.

    opened by dusktreader 6
  • Flask 2.0 Support

    Flask 2.0 Support

    Hello, Flask 2.0 was recently released however I'm unable to upgrade my application due to praetorian requiring flask <2.0: https://github.com/dusktreader/flask-praetorian/blob/master/poetry.lock#L196

    I'm not familiar with Poetry - but it seems like it's flask-buzz that has the <2.0 requirement for flask?

    If you can help confirm whether a change needs to be made to buzz and/or praetorian then I'm happy to help from there.

    Thanks!

    opened by dsposito-ubtech 5
  • API Documentation does not actually list any functions

    API Documentation does not actually list any functions

    On the main page, if you scroll down to the "API" section and click on it (link here), it lists the modules, but not any of the actual functions or decorators.

    opened by McIntireEvan 5
  • Token access_lifespan override not working

    Token access_lifespan override not working

    I've noticed in a few implementations that the token provides an expiration value of 87970022657 (effectively never timing out in the near future). This occurs when JWT_ACCESS_LIFESPAN is provided in the config or not not. I have done some testing and it appears flask-praetorian detects the JWT_ACCESS_LIFESPAN but never overrides it and the default value for expiration when JWT_ACCESS_LIFESPAN is not provided is still 87970022657 and not the default 15 minutes.

    {
      "iat": 1570022657,
      "exp": 87970022657,
      "jti": "21373dcf-0ad4-425c-b4bb-76a00cf1934f",
      "id": "5d923b3623ee32d79594545d",
      "rls": "user,admin",
      "rf_exp": 87970022657
    }
    

    In my configuration I have:

    from flask import Flask, render_template
    from apis import api, blueprint
    from components.resources import guard, User
    from flask_cors import CORS
    
    # Initialize Flask and its config options
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'secret goes here'
    app.config['JWT_ACCESS_LIFESPAN'] = {'minutes': 30}
    app.config['JWT_REFRESH_LIFESPAN'] = {'days': 30}
    app.config['MONGO_URI'] = 'connection string goes here'
    
    # Initialize Flask-Restplus API with BluePrint
    api.init_app(blueprint)
    app.register_blueprint(blueprint)
    
    # Initialize Flask-Praetorian for JWT based authentication and authorization
    guard.init_app(app, User)
    
    # Initialize CORS for remote apps
    CORS(app)
    
    
    if __name__ == '__main__':
        app.run()
    

    The only way I've gotten it to work is to modify flask-praetorian/base.py line 364 to

    if override_access_lifespan is not None:
        access_lifespan = self.access_lifespan
    else:
        access_lifespan = override_access_lifespan
    access_expiration = min(
        (moment + access_lifespan).int_timestamp,
        refresh_expiration,
    )
    
    opened by spennell 5
  • deprecation warning in passlib

    deprecation warning in passlib

    in running tests i get a lot of repeated warnings from flask-praetorian:

    DeprecationWarning: the method passlib.context.CryptContext.encrypt() is deprecated as of Passlib 1.7, and will be removed in Passlib 2.0, use CryptContext.hash() instead.
        return self.pwd_ctx.encrypt(raw_password, scheme=self.hash_scheme)
    

    just a heads up and thanks for the great lib!

    opened by tristanmkernan 5
  • Consider email-based registration mechanism

    Consider email-based registration mechanism

    Creating new users is tricky for an api-based application. It would be nice to have a way to create a new user and provide verification via email.

    I'm not sure this fits into flask-praetorian, but to be a complete batteries-included auth system it might be necessary.

    Think about how something like this could be integrated

    opened by dusktreader 5
  • Add verify_and_update support

    Add verify_and_update support

    We will need the ability to verify a password using it's encryption algorithm and then re-encrypt with a new algorithm. This is necessary if an application decides to switch encryption methods but still needs current passwords to function correctly.

    Hacktoberfest 
    opened by dusktreader 5
  • Fix broken tests with update poetry.lock

    Fix broken tests with update poetry.lock

    cls = <class 'freezegun.api.FakeDatetime'>, tz = datetime.timezone.utc
    
        @classmethod
        def now(cls, tz=None):
            now = cls._time_to_freeze() or real_datetime.now()
            if tz:
    >           result = tz.fromutc(now.replace(tzinfo=tz)) + cls._tz_offset()
    E           ValueError: fromutc: dt.tzinfo is not self
    
    ../../../.cache/pypoetry/virtualenvs/flask-praetorian-IlIQAbrd-py3.8/lib/python3.8/site-packages/freezegun/api.py:358: ValueError
    
    opened by dusktreader 4
  • send_reset_email. How are people adding your custom email templates?

    send_reset_email. How are people adding your custom email templates?

    I'm just checking in to see how you're sending your email template for the verification.

    I have it working and sending the default verification email which is fine. I've created a HTML template now though and want to use it instead.

    Following the docs it says to do as so:

    send_reset_email(email, template=None, reset_sender=None, reset_uri=None, subject=None, override_access_lifespan=None)
    

    so I did:

    guard.send_registration_email(user.username, user=user, template="path.to.template.html")
    

    Stupid me, the email came in, with path.to.template.html in the body. So I get that. String.

    I've tried to somehow get it to the path of the file like so:

    .flask_api/blueprints/auth/templates/new_registration_email.html
    

    ...however I get a 500 INTERNAL SERVER ERROR with "details": "'str' object has no attribute 'new_registration_email'".

    I can't imagine I have to put the complete html in the send_registration_email and I can't find anything in the docs, so I'm a little stumped.

    How are you adding your HTML template in this case?

    Any advice greatly appreciated. Thank you

    opened by therealrobster 4
  • Bump certifi from 2021.10.8 to 2022.12.7

    Bump certifi from 2021.10.8 to 2022.12.7

    Bumps certifi from 2021.10.8 to 2022.12.7.

    Commits

    Dependabot compatibility score

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


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • `PRAETORIAN_RESET_SENDER` might be an optional configure argument?

    `PRAETORIAN_RESET_SENDER` might be an optional configure argument?

    https://github.com/dusktreader/flask-praetorian/blob/c23d10e0d6e34b2b3102b9b71e48f006b8397467/flask_praetorian/base.py#L243

        self.reset_sender = app.config.get(
            "PRAETORIAN_RESET_SENDER",
        )
    

    might can be replace by:

    ...
    DEFAULT_SENDER = app.config.get(
                    "DEFAULT_SENDER"
                )
    ...
        self.reset_sender = app.config.get(
            "PRAETORIAN_RESET_SENDER",
            DEFAULT_SENDER 
        )
    

    IPO,the only DEFAULT_SENDER can meet the needs of sending mail. If the application need to use different mail sender, they can further set them separately?

    opened by imoyao 1
  • encoding a jwt and specifying the override_access_lifespan parameter

    encoding a jwt and specifying the override_access_lifespan parameter

    When encoding a jwt and specifying the override_access_lifespan parameter using a dictionary as per the documentation, an error is thrown: (unsupported operand type(s) for +: 'DateTime' and 'dict') I solved the problem by using datetime.timedelta() to set the override_access_lifespan parameter. I suggest either add a check in encode_jwt_token method as you did with the JWT_ACCESS_LIFESPAN:

    if isinstance(self.access_lifespan, dict): self.access_lifespan = pendulum.duration(**self.access_lifespan)

    or mention in the documentation that it should be of type timedelta.

    thank you ,

    opened by iqmia 1
  • Add integration tests

    Add integration tests

    The project needs to have integration tests that verify that each feature works with:

    • A running flask API instance
    • A running database

    The unit tests should verify that requests to the API get proper responses

    Look into spinning up resources in Docker using the docker python sdk.

    opened by dusktreader 0
  • Dusktreader/226  send reset email is referencing a non existent user attribute

    Dusktreader/226 send reset email is referencing a non existent user attribute

    The email methods needed some hardening and there were some assumptions baked in that needed to be corrected. For now, the functionality has been updated, and documentation will follow. I will need to do some integration and regression testing on this feature.

    opened by dusktreader 0
  • send_reset_email is referencing a non existent User attribute

    send_reset_email is referencing a non existent User attribute

    https://github.com/dusktreader/flask-praetorian/blob/4740713858965e4c933b12e7d33d8972cd1d5618/flask_praetorian/base.py#L896-L899

    send_reset_email attempts to pass the attribute user.email to the function send_token_email. The User object may not necessarily have an email attribute (I for instance have set it up as username in my model), and is causing the execution of send_reset_email to fail.

    Can we update the function to return email instead of user.email? Similar to how its currently done for send_registration_email https://github.com/dusktreader/flask-praetorian/blob/4740713858965e4c933b12e7d33d8972cd1d5618/flask_praetorian/base.py#L827-L831

    opened by sathyanmurugan 5
Boilerplate/Starter Project for building RESTful APIs using Flask, SQLite, JWT authentication.

auth-phyton Boilerplate/Starter Project for building RESTful APIs using Flask, SQLite, JWT authentication. Setup Step #1 - Install dependencies $ pip

sandhika 0 Aug 3, 2022
Flask JWT Router is a Python library that adds authorised routes to a Flask app.

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

Joe Gasewicz 52 Jan 3, 2023
An open source Flask extension that provides JWT support (with batteries included)!

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

Landon Gilbert-Bland 1.4k Jan 4, 2023
A full Rest-API With Oauth2 and JWT for request & response a JSON file Using FastAPI and SQLAlchemy 🔑

Pexon-Rest-API A full Rest-API for request & response a JSON file, Building a Simple WorkFlow that help you to Request a JSON File Format and Handling

Yasser Tahiri 15 Jul 22, 2022
Quick and simple security for Flask applications

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

Matt Wright 1.6k Dec 19, 2022
Quick and simple security for Flask applications

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

Matt Wright 1.6k Feb 17, 2021
Django Auth Protection This package logout users from the system by changing the password in Simple JWT REST API.

Django Auth Protection Django Auth Protection This package logout users from the system by changing the password in REST API. Why Django Auth Protecti

Iman Karimi 5 Oct 26, 2022
Auth-Starters - Different APIs using Django & Flask & FastAPI to see Authentication Service how its work

Auth-Starters Different APIs using Django & Flask & FastAPI to see Authentication Service how its work, and how to use it. This Repository based on my

Yasser Tahiri 7 Apr 22, 2022
Storefront - A store App developed using Django, RESTFul API, JWT

Storefront A store App developed using Django, RESTFul API, JWT. SQLite has been

Muhammad Algshy 1 Jan 7, 2022
The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.

Authlib The ultimate Python library in building OAuth and OpenID Connect servers. JWS, JWK, JWA, JWT are included. Authlib is compatible with Python2.

Hsiaoming Yang 3.4k Jan 4, 2023
FastAPI extension that provides JWT Auth support (secure, easy to use, and lightweight)

FastAPI JWT Auth Documentation: https://indominusbyte.github.io/fastapi-jwt-auth Source Code: https://github.com/IndominusByte/fastapi-jwt-auth Featur

Nyoman Pradipta Dewantara 468 Jan 1, 2023
The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.

Authlib The ultimate Python library in building OAuth and OpenID Connect servers. JWS, JWK, JWA, JWT are included. Authlib is compatible with Python2.

Hsiaoming Yang 2.3k Feb 17, 2021
Django Rest Framework App wih JWT Authentication and other DRF stuff

Django Queries App with JWT authentication, Class Based Views, Serializers, Swagger UI, CI/CD and other cool DRF stuff API Documentaion /swagger - Swa

Rafael Salimov 4 Jan 29, 2022
Authentication with fastapi and jwt cd realistic

Authentication with fastapi and jwt cd realistic Dependencies bcrypt==3.1.7 data

Fredh Macau 1 Jan 4, 2022
CheckList-Api - Created with django rest framework and JWT(Json Web Tokens for Authentication)

CheckList Api created with django rest framework and JWT(Json Web Tokens for Aut

shantanu nimkar 1 Jan 24, 2022
JWT authentication for Pyramid

JWT authentication for Pyramid This package implements an authentication policy for Pyramid that using JSON Web Tokens. This standard (RFC 7519) is of

Wichert Akkerman 73 Dec 3, 2021
Brute force a JWT token. Script uses multithreading.

JWT BF Brute force a JWT token. Script uses multithreading. Tested on Kali Linux v2021.4 (64-bit). Made for educational purposes. I hope it will help!

Ivan Šincek 5 Dec 2, 2022
Djagno grpc authentication service with jwt auth

Django gRPC authentication service STEP 1: Install packages pip install -r requirements.txt STEP 2: Make migrations and migrate python manage.py makem

Saeed Hassani Borzadaran 3 May 16, 2022
JWT Key Confusion PoC (CVE-2015-9235) Written for the Hack the Box challenge - Under Construction

JWT Key Confusion PoC (CVE-2015-9235) Written for the Hack the Box challenge - Under Construction This script performs a Java Web Token Key Confusion

Alex Fronteddu 1 Jan 13, 2022