Stage 3 · Build
Authentication & Authorization
Role-Based Access Control
Model users, roles, permissions, resource ownership, policy checks, and admin audit trails.
RBAC Overview
Role-Based Access Control assigns permissions to roles, and roles to users. Instead of checking individual permissions on every request, you check the user's role. This scales better than per-user permissions and is easier to audit.
Data Model
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(50) NOT NULL UNIQUE,
description TEXT
);
CREATE TABLE user_roles (
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
role_id UUID REFERENCES roles(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, role_id)
);
CREATE TABLE permissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL UNIQUE,
resource VARCHAR(100) NOT NULL,
action VARCHAR(50) NOT NULL
);
CREATE TABLE role_permissions (
role_id UUID REFERENCES roles(id) ON DELETE CASCADE,
permission_id UUID REFERENCES permissions(id) ON DELETE CASCADE,
PRIMARY KEY (role_id, permission_id)
);This is the standard RBAC schema. Users have roles, roles have permissions. The many-to-many tables allow flexible assignment.
Policy Checks
Resource Ownership
Users should only access resources they own unless they have admin permissions. Ownership checks prevent users from reading or modifying other users' data.
Admin Roles
Admin roles need special handling. They can access all resources and perform destructive operations. Log all admin actions for audit purposes.
Audit Trails
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
actor_id UUID NOT NULL REFERENCES users(id),
action VARCHAR(100) NOT NULL,
resource_type VARCHAR(100) NOT NULL,
resource_id UUID,
details JSONB,
ip_address INET,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_audit_logs_actor ON audit_logs(actor_id);
CREATE INDEX idx_audit_logs_resource ON audit_logs(resource_type, resource_id);
CREATE INDEX idx_audit_logs_created ON audit_logs(created_at);Audit logs record who did what, when, and where. Index by actor and resource for fast lookups. Use JSONB for flexible details.
RBAC is not enough alone. Combine role checks, ownership verification, input validation, and rate limiting. Each layer catches different attack vectors.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.