Skip to main content

OAuth2/OIDC authentication and authorization for Flask APIs. Supports authentication and claim-based fine-grained authorization (scopes, roles, permissions) using JWT tokens.

Project description

axioms-flask-py PyPI Pepy Total Downloads

OAuth2/OIDC authentication and authorization for Flask APIs. Supports authentication and claim-based fine-grained authorization (scopes, roles, permissions) using JWT tokens.

Works with access tokens issued by various authorization servers including AWS Cognito, Auth0, Okta, Microsoft Entra, etc.

Using FastAPI or Django REST Framework? This package is specifically for Flask. For FastAPI applications, use axioms-fastapi. For DRF applications, use axioms-drf-py.

GitHub Release GitHub Actions Test Workflow Status PyPI - Version Python Wheels Python Versions GitHub last commit PyPI - Status License PyPI Downloads

Features

  • JWT token validation with automatic public key retrieval from JWKS endpoints
  • Algorithm validation to prevent algorithm confusion attacks (only secure asymmetric algorithms allowed)
  • Issuer validation (iss claim) to prevent token substitution attacks
  • Authorization decorators for standard claims: scopes, roles, and permissions
  • Flexible configuration with support for custom JWKS and issuer URLs
  • Simple integration with Flask based Resource Server or API backends
  • Support for custom claim and/or namespaced claims names to support different authorization servers

Prerequisite

  • Python 3.7+
  • An OAuth2/OIDC client which can obtain access token after user's authentication and authorization and include obtained access token as bearer in Authorization header of all API request sent to Python/Flask application server.

Install SDK

Install axioms-flask-py in you Flask API project,

pip install axioms-flask-py

Documentation

Prerequisite

  • Python 3.7+
  • An Axioms client which can obtain access token after user's authentication and authorization and include obtained access token as bearer in Authorization header of all API request sent to Python/Flask application server.

Install SDK

Install axioms-flask-py in you Flask API project,

pip install axioms-flask-py

Add environment variables

Create a .env file and add following configs (see .env.example for reference)

Option 1: Using AXIOMS_DOMAIN (Recommended - simplest configuration)

AXIOMS_AUDIENCE=<your-axioms-resource-identifier-or-endpoint>
AXIOMS_DOMAIN=<your-axioms-slug>.axioms.io

Option 2: Custom issuer URL (when your issuer includes a path)

AXIOMS_AUDIENCE=<your-axioms-resource-identifier-or-endpoint>
AXIOMS_ISS_URL=https://my-auth.domain.com/oauth2

Option 3: Explicit JWKS URL (for non-standard JWKS endpoints)

AXIOMS_AUDIENCE=<your-axioms-resource-identifier-or-endpoint>
AXIOMS_JWKS_URL=https://my-auth.domain.com/.well-known/jwks.json

For more information see API documentation.

Load environment variables

In your Flask app file (where flask app is declared) add following.

from flask_dotenv import DotEnv
env = DotEnv(app)

Register Error Handler

In your Flask app file (where flask app is declared), register the error handler.

from axioms_flask.error import register_axioms_error_handler

register_axioms_error_handler(app)

Guard Your Flask API Views

Use following decorators to guard you API views.

Decorators Description Parameter
axioms_flask.decorators.
has_valid_access_token
Checks if API request includes a valid bearer access token as authorization header. Check performed includes: token signature validation, expiry datetime validation, token audience validation, and issuer validation (if configured). Should be always the first decorator on the protected or private view.
axioms_flask.decorators.
has_required_scopes
Check any of the given scopes included in scope claim of the access token. Should be after has_valid_access_token. An array of strings as conditional OR representing any of the allowed scope or scopes for the view as parameter. For instance, to check openid or profile pass ['profile', 'openid'] as parameter.
axioms_flask.decorators.
has_required_roles
Check any of the given roles included in roles claim of the access token. Should be after has_valid_access_token. An array of strings as conditional OR representing any of the allowed role or roles for the view as parameter. For instance, to check sample:role1 or sample:role2 roles you will pass ['sample:role1', 'sample:role2'] as parameter.
axioms_flask.decorators.
has_required_permissions
Check any of the given permissions included in permissions claim of the access token. Should be after has_valid_access_token. An array of strings as conditional OR representing any of the allowed permission or permissions for the view as parameter. For instance, to check sample:create or sample:update permissions you will pass ['sample:create', 'sample:update'] as parameter.

OR vs AND Logic

By default, authorization decorators use OR logic - the token must have at least ONE of the specified claims. To require ALL claims (AND logic), chain multiple decorators.

OR Logic (Default) - Requires ANY of the specified claims:

@app.route('/api/resource')
@has_valid_access_token
@has_required_scopes(['read:resource', 'write:resource'])
def resource_route():
    # User needs EITHER 'read:resource' OR 'write:resource' scope
    return {'data': 'success'}

@app.route('/admin/users')
@has_valid_access_token
@has_required_roles(['admin', 'superuser'])
def admin_route():
    # User needs EITHER 'admin' OR 'superuser' role
    return {'users': []}

AND Logic (Chaining) - Requires ALL of the specified claims:

@app.route('/api/strict')
@has_valid_access_token
@has_required_scopes(['read:resource'])
@has_required_scopes(['write:resource'])
def strict_route():
    # User needs BOTH 'read:resource' AND 'write:resource' scopes
    return {'data': 'requires both scopes'}

@app.route('/admin/critical')
@has_valid_access_token
@has_required_roles(['admin'])
@has_required_roles(['superuser'])
def critical_route():
    # User needs BOTH 'admin' AND 'superuser' roles
    return {'message': 'requires both roles'}

Mixed Logic - Combine OR and AND by chaining:

@app.route('/api/advanced')
@has_valid_access_token
@has_required_scopes(['openid', 'profile'])  # Needs openid OR profile
@has_required_roles(['editor'])               # AND must have editor role
@has_required_permissions(['resource:read', 'resource:write'])  # AND read OR write permission
def advanced_route():
    # User needs: (openid OR profile) AND (editor) AND (read OR write)
    return {'data': 'complex authorization'}

Examples

  • Check openid or profile scope present in the token
from axioms_flask.decorators import has_valid_access_token, has_required_scopes

private_api = Blueprint("private_api", __name__)

@private_api.route('/private', methods=["GET"])
@has_valid_access_token
@has_required_scopes(['openid', 'profile'])
def api_private():
    return jsonify({'message': 'All good. You are authenticated!'})
  • Check sample:role role present in the token
from axioms_flask.decorators import has_valid_access_token, has_required_roles

role_api = Blueprint("role_api", __name__)

@role_api.route("/role", methods=["GET", "POST", "PATCH", "DELETE"])
@has_valid_access_token
@has_required_roles(["sample:role"])
def sample_role():
    if request.method == 'POST':
        return jsonify({"message": "Sample created."})
    if request.method == 'PATCH':
        return jsonify({"message": "Sample updated."})
    if request.method == 'GET':
        return jsonify({"message": "Sample read."})
    if request.method == 'DELETE':
        return jsonify({"message": "Sample deleted."})
  • Check permission present in the token at API method level
from axioms_flask.decorators import has_valid_access_token, has_required_permissions

permission_api = Blueprint("permission_api", __name__)

@permission_api.route("/permission", methods=["POST"])
@has_valid_access_token
@has_required_permissions(["sample:create"])
def sample_create():
    return jsonify({"message": "Sample created."})


@permission_api.route("/permission", methods=["PATCH"])
@has_valid_access_token
@has_required_permissions(["sample:update"])
def sample_update():
    return jsonify({"message": "Sample updated."})


@permission_api.route("/permission", methods=["GET"])
@has_valid_access_token
@has_required_permissions(["sample:read"])
def sample_read():
    return jsonify({"message": "Sample read."})


@permission_api.route("/permission", methods=["DELETE"])
@has_valid_access_token
@has_required_permissions(["sample:delete"])
def sample_delete():
    return jsonify({"message": "Sample deleted."})

Flask Sample

To see a complete working example download Flask sample from our Github repository or simply deploy to heroku by clicking following button. You will need to provide Axioms domain and Axioms audience to complete deployment.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

axioms_flask_py-0.0.19rc91762741672.tar.gz (39.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

axioms_flask_py-0.0.19rc91762741672-py3-none-any.whl (14.8 kB view details)

Uploaded Python 3

File details

Details for the file axioms_flask_py-0.0.19rc91762741672.tar.gz.

File metadata

File hashes

Hashes for axioms_flask_py-0.0.19rc91762741672.tar.gz
Algorithm Hash digest
SHA256 bb324a7b5f8d3dc8f9fae96529a20b52d2fea6be3585793eb8492fcf8d019874
MD5 691cd5200a379e1167815fa4f2a56ef2
BLAKE2b-256 510c4f3fd44cc477c80d43bcc16767401931512810222f54d2c933421871f8ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for axioms_flask_py-0.0.19rc91762741672.tar.gz:

Publisher: release.yml on abhishektiwari/axioms-flask-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file axioms_flask_py-0.0.19rc91762741672-py3-none-any.whl.

File metadata

File hashes

Hashes for axioms_flask_py-0.0.19rc91762741672-py3-none-any.whl
Algorithm Hash digest
SHA256 d4f1e5f7e0c42815e00328b99d90a3053db6bd01277c87f1f48e98bb8f1cac6a
MD5 2951c7ffcdbc942bab1e1db9c3935719
BLAKE2b-256 324550510c6b830ea602e9b7955f03a542c1cbb78900f6a5d689f36c4e5c4fa9

See more details on using hashes here.

Provenance

The following attestation bundles were made for axioms_flask_py-0.0.19rc91762741672-py3-none-any.whl:

Publisher: release.yml on abhishektiwari/axioms-flask-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page