Concepts
This page explains the core concepts and architecture of the Auth authorization system.
Core Concepts
Role-Based Access Control (RBAC)
Auth implements a classic RBAC model with three main entities:
- Users
Individuals or entities that need access to resources. Users are identified by unique identifiers (typically email addresses or usernames).
- Roles
Named collections of permissions. Roles represent job functions or access levels (e.g., “admin”, “editor”, “viewer”).
- Permissions
Atomic capabilities or actions that can be performed (e.g., “edit_content”, “delete_user”, “view_reports”).
The RBAC Model
Users (membership)> Roles (permission)> Permissions
Example:
alice@example.com > admin > manage_users
> edit_content
> view_content
bob@example.com > editor > edit_content
> view_content
Users are assigned to roles via memberships, and roles are granted permissions. A user inherits all permissions from their assigned roles.
Client Keys
Every application or service using Auth must have a unique client key (UUID4). This provides:
- Isolation
Different clients have separate authorization scopes. One client’s roles and permissions don’t affect another’s.
- Multi-tenancy
Multiple applications can share the same Auth instance without interfering with each other.
- Security
Client keys act as API authentication tokens when using the REST interface.
Example:
import uuid
# Each app/service gets its own client key
webapp_key = str(uuid.uuid4())
api_service_key = str(uuid.uuid4())
workflow_engine_key = str(uuid.uuid4())
# They operate in isolated scopes
webapp_auth = Authorization(webapp_key)
api_auth = Authorization(api_service_key)
Architecture
Layered Architecture
Auth follows a clean, layered architecture:
API Layer (Flask)
- REST endpoints
- Request validation
- Response formatting
,
?
Service Layer (Business Logic)
- Authorization rules
- Permission checking
- Audit logging
,
?
Data Access Layer (DAL)
- SQLAlchemy ORM
- Database abstraction
- Encryption/Decryption
,
?
Database (SQLite/PostgreSQL)
- User data
- Role & Permission mappings
- Audit logs
Components
- Authorization Service (``AuthorizationService``)
Core business logic for RBAC operations. Handles permission checks, role assignments, and membership management.
- Database Layer (``database.py``)
SQLAlchemy-based ORM models and database connections. Supports both SQLite and PostgreSQL.
- REST API (``routes.py``)
Flask routes providing HTTP endpoints for all authorization operations.
- Client Libraries
Authorization- Direct Python library interfaceEnhancedAuthClient- REST API client for remote access
- Security Components
JWT Authentication
Field-level encryption
Input validation and sanitization
Audit logging
Data Model
Database Tables
- auth_group
Stores roles with their descriptions.
CREATE TABLE auth_group ( id INTEGER PRIMARY KEY, creator TEXT NOT NULL, role TEXT NOT NULL, description TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(creator, role) );
- auth_permission
Maps permissions to roles.
CREATE TABLE auth_permission ( id INTEGER PRIMARY KEY, creator TEXT NOT NULL, group_id INTEGER NOT NULL, name TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (group_id) REFERENCES auth_group(id) ON DELETE CASCADE, UNIQUE(creator, group_id, name) );
- auth_membership
Maps users to roles.
CREATE TABLE auth_membership ( id INTEGER PRIMARY KEY, creator TEXT NOT NULL, group_id INTEGER NOT NULL, user TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (group_id) REFERENCES auth_group(id) ON DELETE CASCADE, UNIQUE(creator, group_id, user) );
- auth_audit_log
Records all authorization changes for compliance and auditing.
CREATE TABLE auth_audit_log ( id INTEGER PRIMARY KEY, client_key TEXT NOT NULL, action TEXT NOT NULL, entity_type TEXT NOT NULL, entity_id TEXT, details TEXT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
Permission Checking
How Permission Checks Work
When you call user_has_permission(user, permission):
Find all roles the user belongs to (via
auth_membership)For each role, query all permissions (via
auth_permission)Check if the requested permission exists in the result set
Return
Trueif found,Falseotherwise
Example:
# Setup
auth.add_role('editor')
auth.add_permission('editor', 'edit_content')
auth.add_membership('bob@example.com', 'editor')
# Check
can_edit = auth.user_has_permission('bob@example.com', 'edit_content')
# Returns: True
# Behind the scenes:
# 1. Query: bob@example.com ? ['editor']
# 2. Query: 'editor' ? ['edit_content', ...]
# 3. Check: 'edit_content' in ['edit_content', ...] ? True
Query Methods
Auth provides several ways to query authorization data:
User-centric queries:
get_user_roles(user)- Get all roles for a userget_user_permissions(user)- Get all permissions for a useruser_has_permission(user, permission)- Check if user has permission
Role-centric queries:
get_role_members(role)- Get all users in a roleget_permissions(role)- Get all permissions for a rolehas_permission(role, permission)- Check if role has permission
Permission-centric queries:
which_users_can(permission)- Find all users with a permissionwhich_roles_can(permission)- Find all roles with a permission
Audit Trail
Every authorization change is logged to the audit table:
Logged Actions:
Role creation/deletion
Permission grant/revoke
Membership addition/removal
Audit Record Fields:
client_key- Which client made the changeaction- Type of operation (create, delete, grant, revoke)entity_type- What was modified (role, permission, membership)entity_id- Identifier of the entitydetails- Additional context (JSON)timestamp- When the change occurred
Example audit log query:
from auth.audit import query_audit_logs
# Get all changes by a client
logs = query_audit_logs(client_key='abc-123')
# Get all permission grants
logs = query_audit_logs(action='grant', entity_type='permission')
Security Model
Defense in Depth
Auth employs multiple security layers:
Client Authentication - UUID4 keys for API access
JWT Tokens - Optional token-based authentication
Input Validation - Sanitization of all user inputs
SQL Injection Protection - ORM-based queries
Encryption - Optional field-level encryption
Audit Logging - Complete change history
Encryption
Auth supports deterministic field-level encryption:
What’s Encrypted:
User identifiers in memberships
Permission names
Optional role descriptions
Why Deterministic:
Allows querying encrypted data
Same plaintext = same ciphertext
Enables efficient database operations
Trade-offs:
Pattern analysis possible (acceptable for usernames/permissions)
Full database functionality maintained
No performance impact on queries
See Encryption for detailed information.
Best Practices
Role Design
Keep roles granular:
# Good: Specific roles
auth.add_role('content_editor')
auth.add_role('content_reviewer')
auth.add_role('content_publisher')
# Avoid: Too broad
auth.add_role('content_manager') # Too many permissions
Use hierarchical naming:
auth.add_role('admin.system')
auth.add_role('admin.department')
auth.add_role('user.premium')
auth.add_role('user.basic')
Permission Design
Use verb-noun naming:
# Good: Clear action + resource
auth.add_permission('role', 'create_user')
auth.add_permission('role', 'delete_post')
auth.add_permission('role', 'view_analytics')
# Avoid: Ambiguous
auth.add_permission('role', 'users')
auth.add_permission('role', 'manage')
Keep permissions atomic:
# Good: Specific permissions
'read_file'
'write_file'
'delete_file'
# Avoid: Combined permissions
'file_management' # Too broad
Client Key Management
Generate unique keys per service:
import uuid
# Different key for each service
web_app_key = str(uuid.uuid4())
mobile_app_key = str(uuid.uuid4())
admin_panel_key = str(uuid.uuid4())
Store keys securely:
Use environment variables
Never commit to version control
Rotate keys periodically
Use secrets management systems in production
Next Steps
Python Usage - Learn the Python API
REST API - Learn the REST API
Security - Security best practices
Audit Logging - Working with audit logs