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 |
|---|---|---|
|
Yes |
Expected audience claim in the JWT token. |
|
No |
Full issuer URL for validating the |
|
No |
Full URL to JWKS endpoint (e.g.,
|
|
No |
Axioms domain name. Used as the base to construct |
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:
AXIOMS_DOMAIN→ constructs →AXIOMS_ISS_URL(if not explicitly set)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/oauthAXIOMS_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:
The
algheader in the JWT specifies an allowed algorithmEach key is used with exactly one algorithm
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
nonealgorithm to bypass signature verificationSubstitute an asymmetric algorithm with a symmetric one
Use weak or deprecated algorithms
Additional Security Features:
Issuer validation (
issclaim) to prevent token substitutionAutomatic 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 |
|---|---|---|
|
No |
List of scope claim names to check in priority order. Default: Example: |
|
No |
List of role claim names to check in priority order. Default: Example: |
|
No |
List of permission claim names to check in priority order. Default: Example: |
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:
Create a
.envfile in your project root (see .env.example for reference)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
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:
AxiomsError – If token is missing or invalid.
Exception – If required config is not set.
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:
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:
- Returns:
Decorator function.
- Return type:
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 missingg.missing_auth_header: True if Authorization header is absentg.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_jwtRequires
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
AxiomsErrorexceptions. The handler returns appropriate HTTP status codes and includes theWWW-Authenticateheader for 401 and 403 responses.The realm in the WWW-Authenticate header uses
get_expected_issuer()which returnsAXIOMS_ISS_URLif configured, otherwise constructs it fromAXIOMS_DOMAINashttps://{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:
MethodViewExtended 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.