A high-performance, multi-tenant Identity and Access Management (IAM) system built with FastAPI, featuring policy-embedded JWT tokens for O(1) authorization, fine-grained access control, and Redis-backed audit logging.
Why HEX IAM? Unlike traditional IAM systems that require a round-trip to check permissions, HEX IAM embeds compact user policies directly in JWT tokens, enabling instant authorization decisions at the edge.
| Feature | HEX IAM | Traditional IAM |
|---|---|---|
| Authorization Latency | O(1) - Policy in token | O(n) - Database lookup |
| Multi-tenancy | Native RLS isolation | Manual filtering |
| Token Revocation | Bloom filter (0.0001% FP) | Database queries |
| Audit Logging | Async Redis Streams | Blocking DB writes |
| Policy Format | Bitwise compact | Verbose JSON |
- API Reference - Complete REST API documentation
- Architecture - System design with diagrams
- BEAMS Example - Reference IGA application built with HEX IAM
# Login (service accounts authentication)
curl -X POST http://localhost:8000/api/v1/authenticate/token \
-H "X-TENANT-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{"email": "admin@acme.com", "password": "SecurePass123!"}'
# Check permission (instant - no DB lookup!)
curl -X POST http://localhost:8000/api/v1/authorize/authorize \
-H "Authorization: Bearer <token>" \
-d '{"action": "read", "resource": "documents"}'
# Response: true (in <1ms)- Multi-Tenant Architecture - PostgreSQL Row-Level Security (RLS) for tenant isolation
- Policy-Embedded JWT - User policies embedded in tokens for O(1) authorization checks
- Fine-Grained Access Control - Bitwise permission system with 12 action types
- High-Performance Responses -
orjsonserialization - Async Audit Logging - Redis Streams with batched writes, zero request blocking
- Token Revocation - Bloom filter for O(1) JTI lookups
- LRU Token Cache - 10,000 token cache for repeated verifications
- OAuth 2.0 / OIDC Identity Provider - Full SSO support with PKCE
HEX IAM includes a complete OAuth 2.0 / OpenID Connect Identity Provider, allowing you to use it as the authentication backend for your applications.
- Authorization Code Flow (with PKCE)
- Client Credentials Flow (service-to-service)
- Refresh Token Flow
| Endpoint | Description |
|---|---|
/api/v1/.well-known/openid-configuration |
OpenID Discovery document |
/api/v1/oidc/jwks |
JSON Web Key Set |
/api/v1/oidc/authorize |
Authorization endpoint |
/api/v1/oidc/token |
Token endpoint |
/api/v1/oidc/userinfo |
User info endpoint |
/api/v1/oidc/logout |
End session endpoint |
/api/v1/oidc/clients |
Client management (CRUD) |
HEX IAM now includes:
identity_providerstable for tenant-trusted external brokers / IdPsfederated_identitiestable for local user linking/api/v1/federation/providers*admin APIsurn:ietf:params:oauth:grant-type:token-exchangesupport on/api/v1/oidc/token
- tenant-owned OIDC clients
- local/native IAM login remains supported
- app-scoped access tokens remain the end state
- authorization stays inside IAM
HEX IAM now supports two distinct federation patterns.
Use this when the application authenticates users against an upstream broker directly, then exchanges the broker token for a tenant-scoped IAM token.
sequenceDiagram
autonumber
actor User
participant App as Client App
participant SSO as Upstream Broker / Hexalgon SSO
participant IAM as HEX IAM
User->>App: Open protected route
App->>SSO: /authorize?client_id=broker-client
SSO->>SSO: Authenticate user / reuse broker session
SSO->>App: Redirect with authorization code
App->>SSO: /token (authorization_code + PKCE)
SSO->>App: Broker identity token
App->>IAM: /api/v1/oidc/token (token-exchange)
IAM->>IAM: Validate broker token + resolve tenant-local user
IAM->>App: Tenant-scoped access token (aud = downstream app client_id)
Use this when the application integrates only with HEX IAM and IAM decides whether to use local login or redirect to a tenant-trusted upstream IdP.
sequenceDiagram
autonumber
actor User
participant App as Client App
participant IAM as HEX IAM
participant UP as Upstream OIDC Provider
User->>App: Open protected route
App->>IAM: /api/v1/oidc/authorize?client_id=downstream-app
IAM->>IAM: Resolve tenant from downstream client_id
alt Local IAM session exists
IAM->>User: Continue consent/code flow
else One upstream provider configured
IAM->>User: Redirect upstream automatically
User->>UP: Authenticate
UP->>IAM: Redirect to federation callback with code
IAM->>IAM: Exchange upstream code, link/provision local user, create IAM session
IAM->>User: Continue consent/code flow
else Multiple upstream providers configured
IAM->>User: Show provider chooser
end
IAM->>App: Redirect with downstream authorization code
App->>IAM: /api/v1/oidc/token
IAM->>App: Tenant-scoped app token
HEX IAM currently supports Hexalgon SSO and other OIDC-compatible upstream identity providers.
SAML is not implemented yet, even though the provider model already reserves a protocol field for it.
GET /api/v1/federation/providersPOST /api/v1/federation/providersGET /api/v1/federation/providers/{provider_id}PATCH /api/v1/federation/providers/{provider_id}DELETE /api/v1/federation/providers/{provider_id}GET /api/v1/federation/providers/{provider_id}/links
POST /api/v1/oidc/token
client_id=<tenant_app_client_id>
client_secret=<tenant_app_client_secret>
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=<broker_platform_token>
audience=<tenant_app_client_id>
issuer_hint=https://sso.hexalgon.local
A tenant-local registry of trusted brokers / IdPs.
Key fields:
tenant_idprotocolissuer_urldiscovery_urljwks_urijwt_validation_secret(bootstrap/dev validation mode)auto_link
Maps an external broker identity to a tenant-local user.
Key fields:
tenant_idprovider_iduser_idexternal_subjectexternal_email
This implementation supports two practical validation paths for broker tokens:
- JWKS / discovery mode - for RS256/ES256 style providers
- Shared secret mode using
jwt_validation_secret- useful for local development and initial bootstrap with the companion SSO repo scaffold
Federated user linking is tenant-scoped.
That means the same email address may exist in multiple tenants, and HEX IAM will only auto-link or provision within the tenant resolved from the downstream app/client flow.
Practical effect:
- the same upstream identity can be linked separately in Tenant A and Tenant B
- roles and policies remain tenant-local
auto_link=truenever causes cross-tenant user linking
Use the Hexalgon SSO companion repo as the global broker. IAM trusts it through an identity_providers entry and exchanges its platform token for a tenant-scoped token.
HEX IAM can now initiate upstream OIDC federation directly from /api/v1/oidc/authorize when one or more tenant-trusted identity providers are configured.
Behavior:
- no local IAM session + one enabled provider -> redirect upstream automatically
- no local IAM session + multiple enabled providers -> show provider chooser
local_login=1-> force native IAM login even when providers exist- upstream callback -> IAM exchanges upstream code, links/provisions local user, sets
hex_iam_session, then resumes at consent
HEX IAM is the tenant-aware identity and authorization layer in the Hexalgon stack.
It now supports two federation modes:
- token exchange from a trusted upstream broker token
- browser-initiated upstream OIDC federation from
/api/v1/oidc/authorize
- App integrates with HEX IAM as its downstream OIDC provider
- Broker/SSO authenticates the user
- HEX IAM links or provisions the tenant-local user and issues the final tenant/app-scoped token
A tenant can configure one or more upstream OIDC identity providers and let IAM:
- redirect the browser to that provider
- handle the callback
- create a local IAM session
- resume consent/code issuance
authorization_scopestoken_endpoint_auth_methodclaims_sourcelink_by_email_verified_onlydefault_role
These improve compatibility with standards-based upstream OIDC providers such as generic enterprise and social IdPs.
Step 1: Register an OAuth Client
curl -X POST http://localhost:8000/api/v1/oidc/clients \
-H "Authorization: Bearer <admin-token>" \
-H "X-TENANT-ID: your-tenant-id" \
-H "Content-Type: application/json" \
-d '{
"name": "My Web App",
"redirect_uris": ["https://myapp.com/callback"],
"scopes": ["openid", "profile", "email"]
}'OR Login via the admin dashboard available at either 5173 or 3000 port and register client apps seamlessly via the intuitive UI
Step 2: Authorization Flow
# 1. Redirect user to authorization endpoint
https://hex-iam.example.com/api/v1/oidc/authorize?
client_id=client_abc123...&
redirect_uri=https://myapp.com/callback&
response_type=code&
scope=openid%20profile%20email&
state=random_state_string&
code_challenge=BASE64URL(SHA256(code_verifier))&
code_challenge_method=S256
# 2. User logs in, approves consent
# 3. HEX IAM redirects back with authorization code
# 4. Exchange code for tokens
curl -X POST http://localhost:8000/api/v1/oidc/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "redirect_uri=https://myapp.com/callback" \
-d "client_id=client_abc123..." \
-d "client_secret=secret_xyz..." \
-d "code_verifier=ORIGINAL_CODE_VERIFIER"Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"id_token": "eyJhbGciOiJIUzI1NiIs..."
}Step 3: Get User Info
curl http://localhost:8000/api/v1/oidc/userinfo \
-H "Authorization: Bearer <access_token>"- PKCE (RFC 7636) - Secure public clients without secrets
- Consent Screen - User-friendly permission approval UI
- Client Management - Full CRUD for OAuth clients
- Scope-based Access -
openid,profile,emailscopes - Discovery Document - Standard OIDC auto-configuration
Python Integration (using Authlib)
from authlib.integrations.requests_client import OAuth2Session
client = OAuth2Session(
client_id='your-client-id',
client_secret='your-client-secret',
redirect_uri='https://myapp.com/callback',
scope='openid profile email'
)
# Get authorization URL
authorization_url, state = client.create_authorization_url(
'https://hex-iam.example.com/api/v1/oidc/authorize'
)
# After user authorizes, exchange code for token
token = client.fetch_token(
'https://hex-iam.example.com/api/v1/oidc/token',
authorization_response=callback_url
)
# Get user info
userinfo = client.get('https://hex-iam.example.com/api/v1/oidc/userinfo').json()Node.js Integration (using Passport)
const passport = require('passport');
const OpenIDConnectStrategy = require('passport-openidconnect').Strategy;
passport.use(new OpenIDConnectStrategy({
issuer: 'https://hex-iam.example.com',
authorizationURL: 'https://hex-iam.example.com/api/v1/oidc/authorize',
tokenURL: 'https://hex-iam.example.com/api/v1/oidc/token',
userInfoURL: 'https://hex-iam.example.com/api/v1/oidc/userinfo',
clientID: 'your-client-id',
clientSecret: 'your-client-secret',
callbackURL: 'https://myapp.com/callback',
scope: ['openid', 'profile', 'email']
},
function(issuer, profile, done) {
return done(null, profile);
}
));See ARCHITECTURE.md for detailed flow diagrams.
| Component | Technology |
|---|---|
| Framework | FastAPI 0.100+ |
| Database | PostgreSQL 15+ with asyncpg |
| Cache/Queue | Redis 7+ with redis-py async |
| Auth | PyJWT, bcrypt, OAuth 2.0/OIDC |
| Serialization | orjson |
| Token Revocation | rbloom (Bloom filter) |
flowchart TD
Client[Client Application]
SSO[Third-Party Apps<br/>via OAuth/OIDC]
Client -->|JWT with embedded policies| Gateway[FastAPI Gateway]
SSO -->|OAuth 2.0 Flow| OIDC[OIDC Provider<br/>/oidc/*]
OIDC -->|Issues Tokens| Gateway
Gateway -->|O1 Authorization Check| AuthZ[Authorization Layer<br/>Bitwise Policy Check]
AuthZ -->|Authenticated Request| DB[(PostgreSQL<br/>RLS Enabled)]
AuthZ -->|Async Audit Log| Redis[(Redis<br/>Streams + Cache)]
Gateway -->|Token Verification| Cache[LRU Token Cache<br/>10,000 tokens]
Gateway -->|Revocation Check| Bloom[Bloom Filter<br/>O1 JTI Lookup]
Redis -->|Batched Write| AuditDB[(Audit Logs Table)]
style AuthZ fill:#00d4aa,stroke:#333,stroke-width:2px,color:#000
style Gateway fill:#009688,stroke:#333,stroke-width:2px,color:#fff
style OIDC fill:#ff6f00,stroke:#333,stroke-width:2px,color:#fff
style Cache fill:#ffd54f,stroke:#333,stroke-width:2px,color:#000
style Bloom fill:#ff6f00,stroke:#333,stroke-width:2px,color:#fff
Key Features:
- O(1) Authorization - Policies embedded in JWT tokens
- Multi-tenant RLS - PostgreSQL Row-Level Security
- Built-in OAuth/OIDC - Complete Identity Provider
- Async Audit Logs - Redis Streams with batched writes
- Token Revocation - Bloom filter for instant checks
- LRU Cache - 10,000 token verification cache
See ARCHITECTURE.md for detailed system design and data flow diagrams.
- Python 3.12+
- PostgreSQL 15+
- Redis 7+
- OR Docker & Docker Compose (recommended for quick start)
The fastest way to get HEX IAM running:
# Clone repository
git clone https://github.com/Merrick1307/identity-access-management-system.git
cd hex-iam
# Copy and configure environment
cp .env.example .env
# Edit .env with your credentials (see Environment Variables below)
# Start all services
docker compose up -d
# View logs
docker compose logs -f hex-iam
# Stop services
docker compose downServices started:
hex-iam- Main API server (port 8000)postgres- PostgreSQL database (port 5432)redis- Redis cache/queue (port 6379)admin-portal- Admin UI (port 3000)
API will be available at: http://localhost:8000
Swagger docs at: http://localhost:8000/docs
# Clone repository
git clone https://github.com/Merrick1307/identity-access-management-system.git
cd hex-iam
# Install dependencies
pip install poetry
poetry install
# Configure environment
cp .env.example .env
# Edit .env with your database credentialsDATABASE_USER= # PostgreSQL username
DATABASE_PASSWORD= # PostgreSQL password
DATABASE_URL= # PostgreSQL connection string (e.g., localhost:5432/dbname)
DATABASE_NAME= # PostgreSQL database name (for initial DB setup)
REDIS_HOST=
REDIS_PORT=
REDIS_USER=
REDIS_PASSWORD=
REDIS_DB= # Redis database index (default: 0)
# Hashing and encryption
JWT_SECRET= # Secret key for JWT signing and authentication
ALGORITHM= # JWT algorithm
ENCRYPT_KEY= # Secret key for encrypting sensitive data
APP_NAME= # Application name
APP_BASE_URL= # Application base URL
# Email Configuration (optional)
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_FROM= # Email sender address
MAIL_PORT= # Email server port
MAIL_SERVER=
#Note: use only one of them below (either should be set to 1 and other to 0)
MAIL_SSL_TLS= # whether to use SSL/TLS
MAIL_STARTTLS= # whether to use STARTTLS Note: use only one of themHEX IAM now uses both:
- Redis Streams for durable audit/revocation replay
- Redis Pub/Sub for immediate cross-node revocation fan-out
Because of that, the Redis ACL user must have channel permissions in addition to key permissions.
Example ACL entry:
user hex-iam on >your-password allcommands allkeys allchannelsA user with only allkeys but no channel permissions will be able to use Streams but will fail with:
No permissions to access a channel
# Development
poetry run uvicorn app.main:app --reload
# Production
poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4Base URL: http://localhost:8000/api/v1
POST /api/v1/authenticate/tokenHeaders:
X-TENANT-ID: your-tenant-uuid
Content-Type: application/json
Request Body:
{
"email": "user@example.com",
"password": "securepassword123"
}Response (200 OK):
{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer"
},
"message": "Authentication successful",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}POST /api/v1/authenticate/logoutHeaders:
Authorization: Bearer <access_token>
Response (200 OK):
{
"success": true,
"message": "Logged out successfully",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}GET /api/v1/authenticate/refreshHeaders:
Authorization: Bearer <access_token>
Response (200 OK):
{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
},
"message": "Token refreshed successfully",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}GET /api/v1/authenticate/sessionsHeaders:
Authorization: Bearer <access_token>
Response (200 OK):
{
"success": true,
"data": [
{
"jti": "user123-1701734400000000000",
"device_info": {"user_agent": "Mozilla/5.0..."},
"ip_address": "192.168.1.1",
"created_at": "2024-12-05T00:00:00+00:00",
"expires_at": "2024-12-05T01:00:00+00:00"
}
],
"message": "Found 1 active sessions",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}POST /api/v1/authenticate/logout-allRevokes ALL active sessions for the current user - JTIs are added to Bloom filter.
Response (200 OK):
{
"success": true,
"data": {"revoked_count": 5},
"message": "Revoked 5 sessions",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}POST /api/v1/authenticate/logout-othersRevokes all sessions except the current one.
Response (200 OK):
{
"success": true,
"data": {"revoked_count": 4},
"message": "Revoked 4 other sessions",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}DELETE /api/v1/authenticate/sessions/{jti}Response: 204 No Content
POST /api/v1/authorize/authorizeHeaders:
Authorization: Bearer <access_token>
Content-Type: application/json
Request Body:
{
"action": "read",
"resource": "documents",
"grant_type": "fga",
"check_condition": false
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
| action | string | Yes | Permission action (read, write, delete, etc.) |
| resource | string | Yes | Resource identifier |
| grant_type | string | No | fga (fine-grained) or rba (role-based). Default: fga |
| check_condition | bool | No | Whether to evaluate policy conditions |
| conditions_to_check | object | Conditional | Required if check_condition is true |
Available Actions:
read, write, delete, approve, reject, execute,
assign, manage, export, import, activate, archive
Response (200 OK):
true // or falsePOST /api/v1/onboarding/tenant/Request Body:
{
"tenant": {
"name": "Acme Corporation",
"domain": "acme.com",
"root": "admin@acme.com"
},
"user": {
"email": "admin@acme.com",
"password": "SecurePass123!",
"first_name": "John",
"last_name": "Doe",
"role": "root"
},
"tenant_policies": [
{
"policy_id": "custom_policy",
"policy": {
"resource": "reports",
"actions": ["read", "export"],
"conditions": {}
}
}
]
}Response (201 Created):
{
"success": true,
"data": {
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "550e8400-e29b-41d4-a716-446655440001",
"tenant_name": "Acme Corporation",
"admin_email": "admin@acme.com",
"verification_email_sent": true,
"message": "Successfully created new tenant - root: admin@acme.com"
},
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}GET /api/v1/onboarding/email/verify?token=<jwt_token>Response (200 OK):
{
"message": "Email verified successfully. You can now log in."
}GET /api/v1/policies/meHeaders:
Authorization: Bearer <access_token>
Response (200 OK):
{
"success": true,
"data": [
{
"policy_id": "admin_access",
"user_id": "uuid",
"tenant_id": "uuid",
"resource": "all",
"actions": ["manage", "write", "delete"],
"conditions": null,
"created_at": "2024-12-05T00:00:00+00:00"
}
],
"message": "Retrieved 1 policies",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}GET /api/v1/policies/user/{user_id}POST /api/v1/policies/user/{user_id}Request Body:
{
"policy_id": "reports_readonly",
"resource": "reports",
"actions": ["read", "export"],
"conditions": {
"department": "finance"
}
}Response (201 Created):
{
"success": true,
"data": {
"policy_id": "reports_readonly",
"user_id": "uuid",
"tenant_id": "uuid",
"resource": "reports",
"actions": ["read", "export"],
"conditions": {"department": "finance"},
"created_at": "2024-12-05T00:00:00+00:00"
},
"message": "Policy 'reports_readonly' created successfully",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}PUT /api/v1/policies/user/{user_id}/{policy_id}Request Body:
{
"actions": ["read", "write", "export"],
"conditions": {
"department": "finance",
"level": "senior"
}
}DELETE /api/v1/policies/user/{user_id}/{policy_id}Response: 204 No Content
POST /api/v1/policies/bulk-assignRequest Body:
{
"user_ids": ["uuid1", "uuid2", "uuid3"],
"policy_id": "viewer_policy",
"resource": "documents",
"actions": ["read"],
"conditions": {}
}Response (201 Created):
{
"success": true,
"data": {
"assigned_count": 3,
"policy_id": "viewer_policy",
"user_ids": ["uuid1", "uuid2", "uuid3"]
},
"message": "Policy assigned to 3 users",
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}DELETE /api/v1/policies/revoke/{user_id}/{policy_id}GET /api/v1/policies/tenant?page=1&page_size=20Policies are embedded in JWT tokens for zero-latency authorization checks.
{
"resource": "documents",
"actions": ["read", "write", "delete"],
"conditions": {
"department": "engineering",
"validity_time": {
"start": "2024-01-01T00:00:00Z",
"end": "2024-12-31T23:59:59Z"
}
}
}{
"sub": "user@example.com",
"user_id": "uuid",
"tenant_id": "uuid",
"role": "admin",
"policy": {
"documents": 7, // READ | WRITE | DELETE = 1 + 2 + 4 = 7
"reports": 257, // READ | EXPORT = 1 + 256 = 257
"all": 255 // Full admin access
},
"exp": 1701734400,
"iat": 1701730800
}| Action | Value | Binary |
|---|---|---|
| READ | 1 | 0000 0000 0001 |
| WRITE | 2 | 0000 0000 0010 |
| DELETE | 4 | 0000 0000 0100 |
| APPROVE | 8 | 0000 0000 1000 |
| REJECT | 16 | 0000 0001 0000 |
| EXECUTE | 32 | 0000 0010 0000 |
| ASSIGN | 64 | 0000 0100 0000 |
| MANAGE | 128 | 0000 1000 0000 |
| EXPORT | 256 | 0001 0000 0000 |
| IMPORT | 512 | 0010 0000 0000 |
| ACTIVATE | 1024 | 0100 0000 0000 |
| ARCHIVE | 2048 | 1000 0000 0000 |
All errors follow this standardized format:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Token has expired",
"path": "/api/v1/authorize/authorize",
"method": "POST"
},
"timestamp": "2024-12-05T00:00:00.000000+00:00"
}| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED |
401 | Authentication required or failed |
FORBIDDEN |
403 | Insufficient permissions |
NOT_FOUND |
404 | Resource not found |
VALIDATION_ERROR |
422 | Invalid request data |
DB_CONNECTION_ERROR |
503 | Database unavailable |
INTERNAL_ERROR |
500 | Unexpected server error |
tenants- Organization accountsusers- User accounts with tenant associationuser_policies- Per-user policy assignmentstenant_policies- Tenant-wide policy templatesaudit_logs- Audit trail (populated from Redis)
All tables use PostgreSQL RLS for automatic tenant isolation:
-- Set tenant context per request
SELECT set_config('app.tenant_id', 'tenant-uuid', true);
-- RLS policy automatically filters
SELECT * FROM users; -- Only returns current tenant's users- LRU Token Cache - 10,000 tokens cached in memory
- Bloom Filter - O(1) revocation check, 0.0001% false positive rate
- Redis Streams - Batched audit writes every 5 seconds
- orjson - 10x faster JSON serialization
- asyncpg - Native PostgreSQL async driver with prepared statements
- Externalized SQL - All queries in
.sqlfiles for maintainability
app/
├── api/
│ └── v1/
│ ├── auth.py # /authenticate endpoints
│ ├── authz.py # /authorize endpoints
│ ├── onboarding.py # /onboarding endpoints
│ ├── otp.py # /otp MFA endpoints
│ ├── policies.py # /policies CRUD endpoints
│ ├── tenants.py # /tenants management
│ └── users.py # /users management
├── audit_logs/
│ ├── redis_logger.py # Redis Streams async logger
│ └── consumer.py # Background log processor
├── core/
│ ├── auth.py # Authentication logic
│ ├── authz.py # Authorization logic (bitwise)
│ ├── jwt_utils.py # JWT create/verify with LRU cache
│ ├── token_revocation.py # Bloom filter revocation manager
│ ├── responses.py # Standardized API responses
│ └── config.py # Environment config
├── database/
│ ├── __init__.py # DB pool, lifespan, RLS context
│ ├── migrations/ # Yoyo database migrations
│ └── queries/ # Externalized SQL queries (.sql files)
├── exceptions/ # Custom exception handlers
├── models/ # Pydantic request/response models
├── services/
│ ├── onboarding.py # Tenant onboarding service
│ ├── otp_service.py # TOTP MFA service
│ └── policy_service.py # Policy management service
├── sso/
│ └── oidc/ # OAuth 2.0 / OIDC Identity Provider
├── templates/
│ ├── oidc/ # OAuth consent/login pages
│ └── onboarding/ # Email templates (HTML)
└── main.py # FastAPI app entry
Release history: see CHANGELOG.md
Note: version metadata in code and package files should be kept in sync with the changelog.
- OAuth 2.1 Compliance - Full RFC 9126 support
- PKCE Enforcement - Mandatory for public clients
- Device Authorization Flow - RFC 8628 for IoT/CLI
- Token Introspection - RFC 7662 endpoint
- RSA/ES256 Support - Asymmetric JWT signing (RS256, ES256)
- Key Rotation - Automated JWKS key rotation
- WebAuthn/Passkeys - Passwordless authentication
- Hardware Key Support - FIDO2/U2F integration
- CLI Tool -
hex-iamcommand-line management - SDK Libraries - Python, JavaScript, Go clients
- Terraform Provider - Infrastructure as code
- OpenAPI Enhancements - SDK generation support
- Prometheus Metrics - Request latency, auth success/failure rates
- OpenTelemetry Tracing - Distributed request tracing
- Webhook Events - Real-time event notifications
- Health Check Endpoints - Kubernetes-ready probes
- Comprehensive Test Suite - >90% coverage
- Performance Benchmarks - Published latency numbers
- Security Audit - Third-party penetration testing
- Production Hardening - Rate limiting, DDoS protection
See Enterprise Edition for features available under commercial license.
We welcome contributions! Please see our contribution guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Documentation: Full Docs
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Security: See SECURITY.md for reporting vulnerabilities
# Run tests
pytest
Need enterprise features? HEX IAM Enterprise(coming soon) will include:
- SAML 2.0 - Enterprise SSO integration
- SCIM Provisioning - Automated user lifecycle management
- Policy Engine - More complex policy evaluation scenarios
- Directory Sync - LDAP/Active Directory integration
- Advanced Audit - Compliance reporting (SOX, HIPAA, GDPR)
- Priority Support - SLA-backed support
- On-Premise Deployment - Full data sovereignty
- Email: muhammedyusufoa@gmail.com
- LinkedIn: Muhammed Yusuf
- GitHub: @Merrick1307
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
- Built with FastAPI
- Inspired by modern authorization patterns from Zanzibar/SpiceDB
- Policy engine design influenced by AWS IAM and OPA