API Reference#

This page contains the full API reference for axioms-flask-py, automatically generated from the source code docstrings.

Core Configuration#

At minimum, axioms-flask-py requires the following environment variables to be configured. For full list of configuration options, see Configuration.

Parameter

Required

Description

AXIOMS_AUDIENCE

Yes

Expected audience claim in the JWT token.

AXIOMS_ISS_URL

No

Full issuer URL for validating the iss claim in JWT tokens (e.g., https://auth.example.com/oauth2). If not provided, constructed as https://{AXIOMS_DOMAIN}. Used to construct AXIOMS_JWKS_URL if that is not explicitly set. Recommended.

AXIOMS_JWKS_URL

No

Full URL to JWKS endpoint (e.g., https://auth.example.com/.well-known/jwks.json). Recommended. If not provided, constructed as {AXIOMS_ISS_URL}/.well-known/jwks.json

AXIOMS_DOMAIN

No

Axioms domain name. Used as the base to construct AXIOMS_ISS_URL if not explicitly provided. This is the simplest configuration option for standard OAuth2/OIDC providers. Not recommended.

Important

Either AXIOMS_JWKS_URL, AXIOMS_ISS_URL, or AXIOMS_DOMAIN must be configured for token validation.

Configuration Hierarchy:

The axioms-flask-py uses the following construction order:

  1. AXIOMS_DOMAIN → constructs → AXIOMS_ISS_URL (if not explicitly set)

  2. AXIOMS_ISS_URL → constructs → AXIOMS_JWKS_URL (if not explicitly set)

Example: Setting only AXIOMS_DOMAIN=auth.example.com/oauth results in:

  • AXIOMS_ISS_URL: https://auth.example.com/oauth

  • AXIOMS_JWKS_URL: https://auth.example.com/oauth/.well-known/jwks.json

Security & Algorithm Validation#

The axioms-flask-py implements multiple security best practices to prevent common JWT attacks:

Algorithm Validation

Only secure asymmetric algorithms are accepted for JWT signature verification. axioms-flask-py validates that:

  1. The alg header in the JWT specifies an allowed algorithm

  2. Each key is used with exactly one algorithm

  3. The algorithm validation occurs before cryptographic operations

Supported Algorithms:

  • RSA: RS256, RS384, RS512

  • ECDSA: ES256, ES384, ES512

  • RSA-PSS: PS256, PS384, PS512

Rejected Algorithms:

  • none - No signature (critical security vulnerability)

  • HS256, HS384, HS512 - Symmetric algorithms (prevents key confusion attacks)

  • Any algorithm not in the allowed list above

This prevents algorithm confusion attacks where an attacker might try to:

  • Use the none algorithm to bypass signature verification

  • Substitute an asymmetric algorithm with a symmetric one

  • Use weak or deprecated algorithms

Additional Security Features:

  • Issuer validation (iss claim) to prevent token substitution

  • Automatic public key retrieval and validation from JWKS endpoints

  • Token expiration validation

  • Audience claim validation

  • Key ID (kid) validation

Claim Name Mapping#

Configure custom claim names to support different authorization servers (AWS Cognito, Auth0, Okta, Microsoft Entra). These mapping options provide additional customization for claim names used to extract scopes, roles, and permissions from the JWT token. These mappings can also support RFC 9068 JWT Profile for OAuth 2.0 Access Tokens.

Parameter

Required

Description

AXIOMS_SCOPE_CLAIMS

No

List of scope claim names to check in priority order.

Default: ['scope']

Example: ['scope', 'scp']

AXIOMS_ROLES_CLAIMS

No

List of role claim names to check in priority order.

Default: ['roles']

Example: ['roles', 'cognito:roles']

AXIOMS_PERMISSIONS_CLAIMS

No

List of permission claim names to check in priority order.

Default: ['permissions']

Example: ['permissions', 'cognito:groups', 'groups', 'entitlements']

Important

Namespaced Claims: You can specify namespaced claim names directly in the claim configuration lists.

The axioms-flask-py will check claims in the order you specify them, using the first non-None value found.

Example: AXIOMS_ROLES_CLAIMS = ['roles', 'https://myapp.com/claims/roles', 'cognito:groups']

Setting Environment Variables#

You can set these environment variables using a .env file with Flask-DotEnv:

  1. Create a .env file in your project root (see .env.example for reference)

  2. Add your configuration:

    # Required
    AXIOMS_AUDIENCE=your-api-audience-or-resource-identifier
    
    # Use AXIOMS_ISS_URL (recommended)
    AXIOMS_ISS_URL=https://your-auth.domain.com
    
    # Explicit JWKS URL (for non-standard JWKS endpoints)
    # AXIOMS_JWKS_URL=https://my-auth.domain.com/oauth2/.well-known/jwks.json
    
  3. Load the environment variables in your Flask app:

    from flask import Flask
    from flask_dotenv import DotEnv
    
    app = Flask(__name__)
    env = DotEnv(app)
    

Alternatively, you can set environment variables directly in your application:

app.config['AXIOMS_AUDIENCE'] = 'your-api-audience'
app.config['AXIOMS_ISS_URL'] = 'https://your-auth.domain.com'
app.config['AXIOMS_JWKS_URL'] = 'https://my-auth.domain.com/oauth2/.well-known/jwks.json'

Decorators#

Decorators for Flask route authentication and authorization.

This module provides decorators for protecting Flask routes with JWT-based authentication and authorization. Supports scope-based, role-based, permission-based, and object-level access control with configurable claim names for different authorization servers.

For complete configuration documentation, see the Configuration section in the API reference.

has_required_scopes(*required_scopes, safe_methods=None)[source]#

Decorator to enforce scope-based authorization.

Checks if the authenticated user’s token contains any of the required scopes. Uses OR logic: the token must have at least ONE of the specified scopes.

To require ALL scopes (AND logic), chain multiple decorators.

Parameters:
  • *required_scopes – Variable length list of required scope strings.

  • safe_methods – List of HTTP methods that bypass authorization (default: from config AXIOMS_SAFE_METHODS or [‘OPTIONS’]).

Returns:

Decorated function that enforces scope check.

Return type:

Callable

Raises:

AxiomsError – If token is missing or doesn’t contain required scopes.

Example

OR logic - requires EITHER scope:

@app.route('/api/resource')
@has_required_scopes('read:resource', 'write:resource')
def protected_route():
    return {'data': 'protected'}

Example

AND logic - requires BOTH scopes via chaining:

@app.route('/api/strict')
@has_required_scopes('read:resource')
@has_required_scopes('write:resource')
def strict_route():
    return {'data': 'requires both scopes'}
has_required_roles(*view_roles, safe_methods=None)[source]#

Decorator to enforce role-based authorization.

Checks if the authenticated user’s token contains any of the required roles. Uses OR logic: the token must have at least ONE of the specified roles.

To require ALL roles (AND logic), chain multiple decorators.

Parameters:
  • *view_roles – Variable length list of required role strings.

  • safe_methods – List of HTTP methods that bypass authorization (default: from config AXIOMS_SAFE_METHODS or [‘OPTIONS’]).

Returns:

Decorated function that enforces role check.

Return type:

Callable

Raises:

AxiomsError – If token is missing or doesn’t contain required roles.

Example

OR logic - requires EITHER role:

@app.route('/admin/users')
@has_required_roles('admin', 'superuser')
def admin_route():
    return {'users': []}

Example

AND logic - requires BOTH roles via chaining:

@app.route('/admin/critical')
@has_required_roles('admin')
@has_required_roles('superuser')
def critical_route():
    return {'message': 'requires both roles'}
has_required_permissions(*view_permissions, safe_methods=None)[source]#

Decorator to enforce permission-based authorization.

Checks if the authenticated user’s token contains any of the required permissions. Uses OR logic: the token must have at least ONE of the specified permissions.

To require ALL permissions (AND logic), chain multiple decorators.

Parameters:
  • *view_permissions – Variable length list of required permission strings.

  • safe_methods – List of HTTP methods that bypass authorization (default: from config AXIOMS_SAFE_METHODS or [‘OPTIONS’]).

Returns:

Decorated function that enforces permission check.

Return type:

Callable

Raises:

AxiomsError – If token is missing or doesn’t contain required permissions.

Example

OR logic - requires EITHER permission:

@app.route('/api/resource')
@has_required_permissions('resource:read', 'resource:write')
def resource_route():
    return {'data': 'success'}

Example

AND logic - requires BOTH permissions via chaining:

@app.route('/api/critical')
@has_required_permissions('resource:read')
@has_required_permissions('resource:admin')
def critical_route():
    return {'message': 'requires both permissions'}
has_valid_access_token(fn=None, *, safe_methods=None)[source]#

Decorator to enforce JWT token authentication.

Validates the JWT access token in the Authorization header and sets the token payload in g.auth_jwt for use in the route handler.

Required config:
  • AXIOMS_AUDIENCE: The expected audience claim

  • AXIOMS_JWKS_URL (or AXIOMS_DOMAIN): JWKS endpoint URL or domain

Parameters:
  • fn – The Flask route function to decorate.

  • safe_methods – List of HTTP methods that bypass authorization (default: from config AXIOMS_SAFE_METHODS or [‘OPTIONS’]).

Returns:

Decorated function that enforces token validation.

Return type:

Callable

Raises:

Example

Has valid access token:

@app.route('/api/protected')
@has_valid_access_token
def protected_route():
    user_id = g.auth_jwt.sub
    return {'user_id': user_id}
check_object_ownership(get_object, owner_field='user', claim_field='sub', inject_as=None, safe_methods=None)[source]#

Decorator to enforce object-level permissions based on ownership.

Verifies that the authenticated user owns the requested object by comparing a field on the object with a claim in the JWT token. Useful for implementing row-level security where users can only access their own data.

Parameters:
  • get_object (Callable) – Callable that fetches the object. Receives same arguments as decorated function. Should raise 404 (abort(404)) if object not found.

  • owner_field (str) – Attribute/key name on the object containing owner identifier (default: “user”).

  • claim_field (str) – Claim name in JWT token containing user identifier (default: “sub”).

  • inject_as (str | None) – Optional parameter name to inject the fetched object into route handler. If None, object is not injected.

  • safe_methods (list | None) – List of HTTP methods that bypass authorization (default: from config AXIOMS_SAFE_METHODS or [‘OPTIONS’]).

Returns:

Decorator function that enforces ownership checking.

Raises:
  • AxiomsError (401) – If user is not authenticated.

  • AxiomsError (400) – If object is missing the owner_field.

  • AxiomsError (403) – If JWT is missing claim_field OR ownership check fails.

  • 404 – If object not found (raised by get_object).

Return type:

Callable

Example

Basic usage with default fields:

def get_article(article_id):
    article = Article.query.get(article_id)
    if not article:
        abort(404)
    return article

@app.patch('/articles/<int:article_id>')
@check_object_ownership(get_article)
def update_article(article_id):
    # Only owner can access
    # article.user must match token.sub
    article = get_article(article_id)
    article.title = request.json['title']
    db.session.commit()
    return {'id': article.id}

With object injection:

@app.patch('/articles/<int:article_id>')
@check_object_ownership(get_article, inject_as='article')
def update_article(article_id, article):
    # article is injected, no need to call get_article again
    article.title = request.json['title']
    db.session.commit()
    return {'id': article.id}

Custom owner field:

def get_comment(comment_id):
    comment = Comment.query.get(comment_id)
    if not comment:
        abort(404)
    return comment

@app.patch('/comments/<int:comment_id>')
@check_object_ownership(get_comment, owner_field='created_by')
def update_comment(comment_id):
    # comment.created_by must match token.sub
    pass

Custom claim field (match by email):

@app.patch('/projects/<int:project_id>')
@check_object_ownership(
    get_project,
    owner_field='owner_email',
    claim_field='email'
)
def update_project(project_id):
    # project.owner_email must match token.email
    pass

Note

  • Works with SQLAlchemy/SQLModel objects (uses getattr)

  • Works with dictionaries (uses .get())

  • Requires middleware or @has_valid_access_token decorator to set g.auth_jwt

require_ownership(owner_field='user', claim_field='sub', safe_methods=None)[source]#

Decorator to check ownership of an object passed as function argument.

Simpler alternative to check_object_ownership when the object is already fetched by the route handler. Checks ownership of the object passed as the first positional argument.

Parameters:
  • owner_field (str) – Attribute/key name on object containing owner ID (default: “user”).

  • claim_field (str) – Claim name in JWT containing user ID (default: “sub”).

  • safe_methods (list | None) – List of HTTP methods that bypass authorization (default: from config AXIOMS_SAFE_METHODS or [‘OPTIONS’]).

Returns:

Decorator function.

Return type:

Callable

Example

Basic usage:

@app.patch('/articles/<int:article_id>')
@require_ownership(owner_field='user')
def update_article(article_id):
    article = Article.query.get_or_404(article_id)
    # Ownership is checked against article
    article.title = request.json['title']
    db.session.commit()
    return {'id': article.id}

Middelware#

Middleware for Flask request authentication.

Provides before_request handler to extract and validate JWT tokens, setting request-scoped attributes for use in route handlers.

setup_token_middleware(app)[source]#

Set up middleware to extract and validate JWT tokens on every request.

This function registers a before_request handler that: 1. Extracts JWT token from Authorization header 2. Validates token signature, expiration, audience, and issuer 3. Sets request-scoped attributes on flask.g for route handlers

Parameters:

app (Flask) – Flask application instance.

Return type:

None

Example

Basic usage:

from flask import Flask, g
from axioms_flask import init_axioms, setup_token_middleware

app = Flask(__name__)
init_axioms(app, AXIOMS_AUDIENCE='my-api', AXIOMS_ISS_URL='...')
setup_token_middleware(app)

@app.route('/protected')
def protected():
    if g.auth_jwt:
        return {'user': g.auth_jwt.sub}
    return {'error': 'Unauthorized'}, 401
Request Attributes Set:

g.auth_jwt: Token payload as Box object if valid, False if invalid, None if missing g.missing_auth_header: True if Authorization header is absent g.invalid_bearer_token: True if Authorization header format is invalid

Note

  • This middleware does NOT reject requests - it only sets attributes

  • Route handlers decide whether to allow access based on g.auth_jwt

  • Requires init_axioms() to be called first for configuration

Error Handling#

Error handling for Axioms authentication and authorization.

register_axioms_error_handler(app)[source]#

Register the Axioms error handler with the Flask application.

This convenience function registers a default error handler for AxiomsError exceptions. The handler returns appropriate HTTP status codes and includes the WWW-Authenticate header for 401 and 403 responses.

The realm in the WWW-Authenticate header uses get_expected_issuer() which returns AXIOMS_ISS_URL if configured, otherwise constructs it from AXIOMS_DOMAIN as https://{AXIOMS_DOMAIN}.

Parameters:

app – Flask application instance.

Example:

from flask import Flask
from axioms_flask.error import register_axioms_error_handler

app = Flask(__name__)
app.config['AXIOMS_AUDIENCE'] = 'your-api-audience'
app.config['AXIOMS_DOMAIN'] = 'auth.example.com'
register_axioms_error_handler(app)

Note

  • 401 responses: Authentication failure (missing/invalid token)

  • 403 responses: Authorization failure (insufficient permissions)

Method View#

The methodview module provides an extended Flask MethodView with per-method decorator support.

Extended MethodView class with per-method decorator support.

class MethodView[source]#

Bases: MethodView

Extended Flask MethodView with method-specific decorator support.

This class extends Flask’s MethodView to allow decorators to be applied to specific HTTP methods (GET, POST, etc.) in addition to the standard class-level decorators.

_decorators#

Dictionary mapping HTTP method names to lists of decorators.

Example:

class UserAPI(MethodView):
    decorators = [has_valid_access_token]  # applies to all methods
    _decorators = {
        'post': [has_required_permissions("user:create")],
        'delete': [has_required_permissions("user:delete")]
    }

    def get(self, user_id):
        return {'user': user_id}

    def post(self):
        return {'created': True}
dispatch_request(*args, **kwargs)[source]#

Dispatch request with method-specific decorators applied.

Overrides the standard MethodView dispatch to apply any decorators defined in _decorators for the current HTTP method.

Parameters:
  • *args – Positional arguments passed to the view method.

  • **kwargs – Keyword arguments passed to the view method.

Returns:

Response from the view method after applying decorators.