Skip to main content

Oceana API library to manage JWT token in Flask Restx applications

Project description

oceana_jwt_auth

Build Status Supported Python Versions PyPI version PyPI - Downloads

Description

oceana-jwt-auth library is designed to be a drop-in solution for adding JWT-based authentication to Flask-RestX applications with minimal configuration while providing extensive customization options for complex security requirements.

Main Features

JWT Token Management

  • Token Creation & Validation: Generate and validate JWT tokens using multiple algorithms (HS256, HS384, HS512, ES256, RS256, etc.)
  • Flexible Token Configuration: Configurable token expiration, issuer, audience, and algorithms
  • RSA Support: Support for RSA public/private key encryption for enhanced security

Flask-RestX Integration

  • Native Integration: Purpose-built for Flask-RestX applications with automatic API documentation
  • Swagger Documentation: Automatic security documentation in Swagger UI with authorization support
  • Namespace Support: Seamless integration with Flask-RestX namespaces and blueprints

Authorization & Authentication

  • Role-Based Access Control (RBAC): Support for user roles and permissions
  • Multi-level Security:
    • @auth_guard(secured=True) - Basic authentication
    • @auth_guard(admin=True) - Admin-level access
    • Custom decorators for specific business logic
  • Identity Management: Built-in user identity and endpoint security models

Database Integration

  • Multiple Database Support:
    • SQLite (for development/testing)
    • PostgreSQL (for production)
    • Configurable via environment variables or connection strings
  • Automatic Schema Management: Auto-creation of security tables (sec_identity, sec_endpoint)
  • SQLAlchemy Integration: Built on Flask-SQLAlchemy for robust ORM support

Configuration Management

  • Environment-Based Configuration: Comprehensive environment variable support
  • Multiple Configuration Classes: Pre-built configurations for different deployment scenarios
  • Flexible Setup: Support for both direct instantiation and application factory patterns

Security Features

  • Cryptographic Utilities: Built-in password hashing, salt generation, and secure string comparison
  • Token Verification: Configurable token verification with custom callbacks
  • Exception Handling: Comprehensive error handling with custom exception types
  • Request Validation: Automatic validation of authorization headers and token format

Production Ready

  • Environment Variable Support: Full 12-factor app compliance (to the Twelve-Factor App methodology
  • Database Connection Pooling: Efficient database connection management
  • Token Refresh: Support for refresh tokens with configurable expiration
  • Configurable Security: Global and per-endpoint security configuration

Developer Experience

  • Logging Integration: Built-in logging with configurable levels and handlers
  • Error Handling Decorators: @handle_exceptions() decorator for consistent error responses
  • Mock Data Support: Built-in tools for testing and development
  • Extensive Examples: Complete usage examples for different scenarios

Installation

Install latest version from PyPI:

pip install oceana_jwt_auth

Usage

Code is provided in examples directory.

Easy Integration:

# Simple setup
from oceana_jwt_auth import JWTExtension, auth_guard

jwt = JWTExtension(app=app, api=api)

@auth_guard(secured=True)
def protected_endpoint():
    return {"message": "Authorized access"}

Create Flask application and JWTExtension:

from oceana_jwt_auth import JWTExtension, auth_guard, info

# App is available globally
app = Flask(__name__)

# Create namespace
ns_test = Namespace("Test", description="Test API", path="/v1")

@ns_test.route("/reader", methods=["GET"])
class TestReader(Resource):
    @auth_guard(secured=True)
    def get(self):
        info("Get endpoint reached")
        return jsonify({"status": "OK", "code": 200})


@ns_test.route("/writer", methods=["GET"])
class TestWriter(Resource):
    @auth_guard(secured=True)
    def get(self):
        info("Get endpoint reached")
        return jsonify({"status": "OK", "code": 200})


bp = Blueprint("test", __name__)
api = Api(
    app=bp,
    title="Test API",
    version="1.0",
    description="Test API",
)

# Add namespace
api.add_namespace(ns_test)

# Register blueprint
app.register_blueprint(bp)

# Create authorization extension from app and api objects
JWTExtension(app=app, api=api)

Create a decorator (also in examples directory):

from oceana_jwt_auth import JWTExtension, ConfigSqlite, info, \
    handle_exceptions, verify_jwt
from oceana_jwt_auth.exceptions import ClientAuthenticationError

# App is available globally
app = Flask(__name__)
# Settings can be set in app configuration 
app.config["REGISTER_AUTH"] = True

# Create namespace
ns_test = Namespace("Test", description="Test API", path="/v1")


def required_last_minutes(minutes=10):
    def wrapper(route_function):
        @wraps(route_function)
        def decorated_function(*args, **kwargs):
            # Verify jwt
            jwt_data, jwt_header = verify_jwt(optional=False)
            # Get roles from jwt
            iat = jwt_data.get("iat")
            iat_dt = datetime.fromtimestamp(iat)
            created = jwt_data.get("created")

            info(f"Token created time: {created}")
            now = datetime.now()
            if (now - iat_dt).total_seconds() < int(minutes)*60:
                return route_function(*args, **kwargs)
            else:
                raise ClientAuthenticationError(f"Invalid JWT: created before {minutes} minutes")
        return decorated_function
    return wrapper


@ns_test.route("/minutes", methods=["GET"])
class TestApp(Resource):
    @handle_exceptions()
    @required_last_minutes(minutes=2)  # User defined decorator
    def get(self):
        info("Get endpoint reached")
        return jsonify({"status": "OK", "code": 200})


bp = Blueprint("test", __name__)
api = Api(
    app=bp,
    title="Test API",
    version="1.0",
    description="Test API",
)

# Add namespace
api.add_namespace(ns_test)

# Register blueprint
app.register_blueprint(bp)

# Create authorization extension from app and api objects
jwt = JWTExtension(app=app, api=api, config_object=ConfigSqlite)

Config authorization witha a Postgres database:

# Import Postgres configuration object
from oceana_jwt_auth import JWTExtension, ConfigPostgres

app[SQLALCHEMY_DATABASE_URI] = "postgresql://postgres:postgres@localhost:5432/oceana_jwt_auth"


JWTExtension(app=app, api=api, config_object=ConfigPostgres)

Connection string can be stored in environment parameters:

# Connection configuration
SQLALCHEMY_DATABASE_URI="postgresql://postgres:postgres@localhost:5432/oceana_jwt_auth"

or:

# Connection configuration
OCEANA_API_DB_AUTH_HOST=localhost
OCEANA_API_DB_AUTH_DATABASE=oceana_jwt_auth
OCEANA_API_DB_AUTH_USERNAME=postgres
OCEANA_API_DB_AUTH_PASSWORD=postgres
OCEANA_API_DB_AUTH_PORT=5432
OCEANA_API_DB_AUTH_SCHEMA=public
OCEANA_API_DB_AUTH_CREATE_ENTITIES=true

Environment

Properties in environment variables:

# Database provider and issuer of JWT tokens
OCEANA_API_PROVIDER=OceanaAPI
# Security properties, it enables global security
OCEANA_API_SECURED=true
# Oceana API Secret key
OCEANA_API_SECRET_KEY=secret_key
# Generate a JWT with valid within 1 hour by now (in minutes)
OCEANA_API_TOKEN_MAX_MINUTES=60

Packaging

Build package

# Using build package
python -m build

Run tests

# All tests
pytest -q -rP

# Partial tests
pytest tests/unit/test_application.py -v -rP
pytest tests/functional/test_validation.py -v -rP
pytest tests/unit/test_common.py -v -rP

# With coverage
coverage run -m pytest tests -v
coverage html
# Reinstall avoiding reinstalling dependencies
pip install --upgrade --no-deps --force-reinstall dist\oceana_jwt_auth-0.0.9-py3-none-any.whl
# Reinstall with dependencies
pip install dist\oceana_jwt_auth-0.0.9-py3-none-any.whl --force-reinstall

Check style guide enforcement

flake8 . --count --exit-zero --max-complexity=10 --max-line-length=120 --statistics

Tox

# Command to test only one python version
tox -e py39

Uninstall

pip uninstall oceana_jwt_auth

Dependencies

Library Version
requests >= 2.29.0
python-decouple == 3.8
flask >= 3.1.0
flask-restx >= 1.3.0
typing-extensions >= 4.12.2
pyjwt >= 2.8.0
SQLAlchemy >= 2.0.36
Flask-SQLAlchemy >= 3.1.1
cryptography >= 41.0.7
psycopg2 >= 2.9.9

Releases

Version 0.0.9:

  • Python upgraded ["3.9", "3.10", "3.11"] -> ["3.12", "3.13", "3.14"]
  • Upgrading libraries dependencies

Version 0.0.8:

  • First version

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

oceana_jwt_auth-0.0.9.tar.gz (34.0 kB view details)

Uploaded Source

Built Distribution

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

oceana_jwt_auth-0.0.9-py3-none-any.whl (35.6 kB view details)

Uploaded Python 3

File details

Details for the file oceana_jwt_auth-0.0.9.tar.gz.

File metadata

  • Download URL: oceana_jwt_auth-0.0.9.tar.gz
  • Upload date:
  • Size: 34.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for oceana_jwt_auth-0.0.9.tar.gz
Algorithm Hash digest
SHA256 a5c53304e8977082d8ac56e0061ca201fc6150497a43dcd0c0432ea625b05499
MD5 0e724ae65c719b485ef8c488b3a909ef
BLAKE2b-256 d9948789f907fd1e489277fe913069ff7dbae55e99f2fb552e301c7b1438d646

See more details on using hashes here.

File details

Details for the file oceana_jwt_auth-0.0.9-py3-none-any.whl.

File metadata

File hashes

Hashes for oceana_jwt_auth-0.0.9-py3-none-any.whl
Algorithm Hash digest
SHA256 0299e37c9441c20fcbb5a9a016aa709c1e4daee4c74e7b2ed9cb0b142d2051a8
MD5 f4718ba7325f1ba9a351f9f6992ad556
BLAKE2b-256 6c023f3d8fcd398c51bbf46b16ae5dd5439bcf8c89d012e943f25601ccecec6c

See more details on using hashes here.

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