CRUMB a card from devarno-cloud

LORE RBAC & Airlock Auth Flow

lore intermediate 6 min read

ELI5

LORE has three types of visitors: admins (who see everything across all organisations), operators (who see everything for their own organisation), and viewers (who can only read). The door guard is a shared system called Airlock that checks everyone’s badge before they enter, using a cookie that works across all devarno websites.

Technical Deep Dive

Role Hierarchy

RoleScopeCapabilities
adminAll orgsFull read across all orgs. Can see all decisions, all agents, all analytics
operatorSingle orgFull read within own org. Sees decisions, agents, analytics scoped to their org
viewerRead-onlyRead-only access to public/org-scoped content. Cannot access admin features

Roles are derived from Airlock’s RBAC system — LORE itself has no local role store. The middleware extracts the airlock session, maps the user’s org memberships and global role flags, and emits x-lore-user-* headers.

Auth Flow

1. Browser requests lore.devarno.cloud
2. LORE middleware reads .devarno.cloud session cookie
3. Middleware calls airlock.devarno.cloud/api/auth/session
4. Airlock validates cookie, returns user + orgs + roles
5. Middleware computes LoreRole from airlock claims
6. Middleware emits x-lore-user-id, x-lore-user-role, x-lore-user-orgs headers
7. Page/API route reads headers to enforce RBAC

Airlock Integration (Pattern A — Same-Apex SSO)

LORE uses the canonical Pattern A integration from the airlock runbook:

  • 3 files needed: middleware.ts, lib/auth.ts, lib/airlock-client.ts
  • ~40 lines of middleware total
  • Zero OIDC client registration needed — cookie is scoped to .devarno.cloud so all same-apex subdomains inherit it
  • clientSlug: "lore" registered in airlock’s trustedOrigins

Role Computation

// Simplified from lore/src/lib/auth.ts
function computeLoreRole(airlockSession): LoreRole {
if (airlockSession.user.roles.includes("admin")) return "admin"
if (airlockSession.user.roles.includes("operator")) return "operator"
return "viewer"
}

Security Properties

  • HttpOnly session cookies (no JS access)
  • Secure (HTTPS only)
  • SameSite=Lax (protects against CSRF while allowing top-level navigation)
  • Cross-subdomain scope (.devarno.cloud domain)
  • No local auth state — LORE is fully stateless; session validation is always live

Key Terms

  • Pattern A → Same-apex SSO: .devarno.cloud cookie inherited by all subdomains, zero OIDC registration
  • clientSlug → Short name registered in airlock’s trustedOrigins"lore" for LORE
  • LoreRole → Computed from airlock user roles: "admin" | "operator" | "viewer"
  • x-lore-user-* → Custom headers emitted by middleware containing user ID, role, and org memberships
  • RBAC → Role-Based Access Control — enforced at both middleware (session gate) and page (role gate) layers

Q&A

Q: Does LORE store its own users table? A: No. All user/role/org data lives in airlock. LORE is fully stateless and derives roles from the session.

Q: How does the middleware forward cookies to airlock? A: It reads the incoming Cookie header, extracts the session cookie, and forwards it in the Cookie header of the airlock validation request.

Q: What happens if airlock is down? A: The middleware cannot validate the session → all requests return a redirect to the login page or a 502 with DegradedBanner (outage).

Examples

LORE’s auth is like a music festival with a central wristband check — you get your wristband once at the entrance (airlock), and every tent (LORE, CAIRNET, hubble, hatch) just checks the wristband colour to know what access you have.

neighbors on the map