Qx auth: JWT validation, OIDC client, RBAC primitives, policy engine, rate limiting
Project description
qx-auth
JWT validation, OIDC discovery, RBAC primitives, policy engine, and token-bucket rate limiting for the Qx framework.
What lives here
qx.auth.JwtValidator— validates and decodes JWT access tokens. Supports RS256/ES256 via JWKS endpoint, audience and issuer validation, and a pluggableRevocationCheck.qx.auth.JwtSettings— Pydantic settings: JWKS URI, issuer, audience, algorithm, leeway.qx.auth.Principal— decoded token claims:subject,email,roles,permissions,tenant_id, raw claims dict.qx.auth.OidcDiscovery— fetches and caches the OpenID Connect discovery document (/.well-known/openid-configuration). PopulatesJwtSettingsfrom the discovery endpoint automatically.qx.auth.OidcConfiguration— parsed OIDC discovery document.qx.auth.Role/Permission— value objects for RBAC.Rolecontains a set ofPermissionstrings with wildcard matching (orders.*matchesorders.read).qx.auth.PolicyEvaluator— evaluates a list ofPolicyobjects against aPrincipal. Policies are composable withrequire_permission,require_any_permission, andrequire_all_permissions.qx.auth.TokenBucket— in-memory token-bucket rate limiter. Returns aTokenBucketResultwithallowed,remaining, andretry_after— no exceptions.
Usage
JWT validation in a FastAPI route
from qx.auth import JwtValidator, Principal
from fastapi import Depends, HTTPException
from fastapi.security import HTTPBearer
security = HTTPBearer()
validator = JwtValidator(settings.jwt)
async def current_principal(token=Depends(security)) -> Principal:
result = await validator.validate(token.credentials)
if not result.is_success:
raise HTTPException(status_code=401)
return result.value
Policy evaluation
from qx.auth import PolicyEvaluator, require_permission
evaluator = PolicyEvaluator([require_permission("users.write")])
decision = evaluator.evaluate(principal)
if not decision.allowed:
return Result.failure(ForbiddenError(...))
Token-bucket rate limiting
from qx.auth import TokenBucket
bucket = TokenBucket(capacity=100, refill_rate=10) # 10 tokens/sec
result = bucket.consume(principal.subject)
if not result.allowed:
return Result.failure(RateLimitedError(retry_after=result.retry_after))
Design rules
JwtValidator.validate()returnsResult[Principal]— it never raises. Callers decide how to translate validation failures to HTTP responses.- JWKS are cached and refreshed lazily on key-ID miss so a key rotation doesn't require a restart.
- Permission wildcards follow a simple dot-separated scheme:
"orders.*"grants all permissions starting with"orders.". Policies compose with AND (require_all_permissions) or OR (require_any_permission) semantics.
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
qx_auth-1.1.0.tar.gz
(14.9 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
qx_auth-1.1.0-py3-none-any.whl
(15.2 kB
view details)
File details
Details for the file qx_auth-1.1.0.tar.gz.
File metadata
- Download URL: qx_auth-1.1.0.tar.gz
- Upload date:
- Size: 14.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53498e61b9c22c2b961c0fa7bdd5da464801aa446a4530a64f435564dfddd465
|
|
| MD5 |
8aa1fbccc8a9783b05040f18c5e6910f
|
|
| BLAKE2b-256 |
a1c2849036bc4c875f772304061eb94864f050b3de99cb825ba0bafb1f28cd59
|
File details
Details for the file qx_auth-1.1.0-py3-none-any.whl.
File metadata
- Download URL: qx_auth-1.1.0-py3-none-any.whl
- Upload date:
- Size: 15.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07ea2ecb15bb64bcde2f109a6c7a8ccdc88b07e4e7fed11c005450aa596b9087
|
|
| MD5 |
ae57d3440b015dd9706bf46ad2f935c8
|
|
| BLAKE2b-256 |
0b0665a5026f9f55401c3b34a80aeedc23b28ea44fdadc5a84328305017adf36
|