Skip to main content

RBAC & Session Cookie Authentication

Role-Based Access Control (RBAC) assigns permissions to roles, then roles to users. Combined with signed session cookies, you get a simple, secure auth system that works without JWT complexity.

badmin

Hono + SQLite — full RBAC admin panel with session cookies.

Cruise Ship

Next.js + PostgreSQL — role-based business system with token sessions.

RBAC Data Model

The classic RBAC model has four tables:

Schema Definition

Permission keys use dot notation (users.read, users.write) for natural grouping. The group column lets you organize them in the UI.
Instead of JWTs, use signed session cookies — simpler, more secure for same-origin apps:

Why Cookies over JWT?

Implementation with Hono

Route Protection

Chain middleware to protect routes:

Session Versioning (Forced Logout)

When a user changes their password or gets disabled, bump their sessionVersion:
When requireSession checks the cookie, it compares the cookie’s version with the DB version. If they differ, the session is rejected.
Session versioning is the simplest way to force logout. No blacklist, no waiting for JWT expiry — just increment a number in the DB.

Loading Permissions into Session

On login, load all the user’s permissions into the session object:

Frontend Permission Checks

Don’t rely only on backend — hide UI elements the user can’t access:
Frontend permission checks are for UX (hide buttons), not security. The backend middleware is the real gatekeeper — always validate permissions on the API side.

Cruise Ship: Token-Based Sessions

For the cruise-ship system (Next.js + PostgreSQL), we used token-based sessions stored in the DB:
This approach stores the full session in PostgreSQL — good for distributed apps where cookie-only sessions can’t work.

Best Practices

  1. Signed cookies over JWT — Simpler, revocable, smaller payload
  2. Session versioning — Increment to force logout on password change or account disable
  3. Flatten permissions — Load all permission keys into the session object for O(1) checks
  4. Exclude sensitive columns — Never query passwordHash into session data
  5. Cascade deletes on M2M — Role/user deletions should auto-clean associations
  6. isSystem flag on roles — Prevent deletion of essential roles (Admin, SuperAdmin)
  7. Frontend hides, backend validates — Frontend checks are UX, backend middleware is security
  8. Token sessions for distributed systems — When cookies can’t work across services, store tokens in DB

References

Last modified on April 19, 2026