Skip to content

RBACX

RBAC + ABAC authorization for Python with a clean architecture, declarative JSON policies, framework adapters, and optional hot reloading.


Inspiration & Philosophy

RBACX is inspired by: - OWASP-aligned practices like deny by default and least privilege. - The recurring pain for Python developers switching between projects with inconsistent authorization stacks. - The XACML model (policies, rules, effects, combining algorithms, obligations), simplified and made friendlier for web developers using JSON and a Python-first API.

Our philosophy: security should be understandable and ergonomic for developers so that correct authorization becomes the path of least resistance.


What you get

  • RBAC + ABAC in a single engine (role checks + attribute conditions).
  • Declarative policies (JSON/YAML or Python dict) with compact operators, including time operators.
  • Secure defaults: deny-overrides by default; also permit-overrides, first-applicable.
  • Role hierarchy via resolvers (StaticRoleResolver and custom implementations).
  • Explainable decisions (allowed, effect, reason, rule_id) and obligations (e.g., require MFA).
  • Hot reload from file/HTTP/S3 using ETag checks.
  • Adapters for FastAPI/Starlette, Flask, Django/DRF, Litestar.
  • Observability: logging hooks and metrics sinks (Prometheus/OpenTelemetry).
  • CLI & linting: rbacx validate to validate policies.
  • Test coverage around 82% across core decision paths.

Quick start

1) Install

pip install rbacx

2) Define a minimal policy (JSON)

{
  "algorithm": "deny-overrides",
  "rules": [
    {
      "id": "allow_read_public",
      "target": { "resource": { "type": "document" }, "action": "read" },
      "condition": { "==": [ { "attr": "resource.visibility" }, "public" ] },
      "effect": "permit",
      "obligations": [{ "type": "require_mfa", "when": true }]
    }
  ]
}

3) Evaluate in Python

from rbacx import Guard

policy = {...}  # load JSON as a dict
g = Guard(policy)

decision = g.evaluate_sync(
    subject={"id": "u1", "roles": ["reader"]},
    action="read",
    resource={"type": "document", "visibility": "public"},
    context={"mfa": True},
)

assert decision.allowed is True
print(decision.effect, decision.reason, decision.rule_id, decision.obligations)

4) (Optional) Use a web adapter

FastAPI

from fastapi import FastAPI
from rbacx.adapters.fastapi import require_access
from rbacx import Guard

app = FastAPI()

policy = {...}  # reuse the policy from above or define one here
guard = Guard(policy)

def build_env(request):
    # map request -> (subject, action, resource, context)
    return {
        "subject": {"id": request.headers.get("X-User"), "roles": ["reader"]},
        "action": request.method.lower(),
        "resource": {"type": "document", "path": request.url.path},
        "context": {"mfa": True},
    }

@app.get("/docs")
@require_access(guard, build_env)
def docs():
    return {"ok": True}


Documentation map

Start here - Quickstart - Why choose RBACX - Highlights

Core concepts - Architecture - Security model - Explainability (reasons & obligations) - Role hierarchy - Audit mode

Policy - Policy authoring - Policy catalog - Time operators - Policy loading (hot reload) - Policy stores - HTTP mapping

Integration - Web adapters - Adapters (API) - Try examples

Observability - Metrics - OpenTelemetry - Logging - Diagnostics - Observability stack

Performance & operations - Performance guide - Benchmarks - CI - Migration (RBAC→ABAC)

Reference - Public API