System Overview
Last Updated: 2026-04-25
High-Level Architecture
Porta is a multi-tenant OIDC identity provider built on Koa + node-oidc-provider + TypeScript. It serves as a complete authentication and user management platform with organization-scoped tenancy, RBAC, custom claims, and two-factor authentication.
Component Overview
Core Runtime
| Component | Technology | Purpose |
|---|---|---|
| HTTP Server | Koa 2.x | Request handling, middleware pipeline |
| OIDC Engine | node-oidc-provider 9.x | OpenID Connect protocol implementation |
| Database | PostgreSQL 16 (pg) | Persistent storage, long-lived OIDC artifacts |
| Cache/Sessions | Redis 7 (ioredis) | Short-lived OIDC artifacts, tenant cache, rate limits |
| Logger | pino | Structured logging (JSON in prod, pretty in dev) |
| Config | zod | Environment validation with fail-fast semantics |
| Signing | jose + crypto | ES256 (ECDSA P-256) token signing |
| CLI | yargs | Admin command-line interface |
| Admin GUI SPA | React 19 + FluentUI v9 | Browser-based admin dashboard |
| Admin GUI BFF | Koa (separate process) | Backend-for-frontend: OIDC auth, session, API proxy |
| Admin GUI Build | Vite | SPA bundler and dev server |
Domain Modules
Porta follows a modular domain architecture where each business domain is encapsulated in its own directory under src/:
| Module | Directory | Responsibility |
|---|---|---|
| Organizations | src/organizations/ | Tenant management, status lifecycle, branding |
| Applications | src/applications/ | SaaS product definitions, module grouping |
| Clients | src/clients/ | OIDC client registration, secret management |
| Users | src/users/ | User accounts, passwords, status lifecycle |
| Auth | src/auth/ | Authentication workflows, magic links, email, templates |
| RBAC | src/rbac/ | Roles, permissions, user-role assignments |
| Custom Claims | src/custom-claims/ | Claim definitions, user claim values |
| Two-Factor | src/two-factor/ | TOTP, email OTP, recovery codes |
| CLI | src/cli/ | Admin CLI with dual-mode bootstrap |
Each domain module follows a consistent internal structure:
src/<module>/
├── index.ts # Barrel export (public API)
├── types.ts # Domain types, interfaces, row mapping
├── errors.ts # Domain-specific error classes
├── repository.ts # PostgreSQL CRUD operations
├── cache.ts # Redis caching layer
├── service.ts # Business logic, validation, orchestration
├── slugs.ts # Slug generation and validation (where applicable)
└── validators.ts # Input validation (where applicable)Admin GUI Module
The Admin GUI is a separate application in admin-gui/ with its own package.json, build pipeline, and test suite. It consists of two layers:
| Layer | Technology | Purpose |
|---|---|---|
React SPA (admin-gui/src/client/) | React 19, FluentUI v9, React Router, React Query | Browser-based admin dashboard |
Koa BFF (admin-gui/src/server/) | Koa, koa-session, ioredis | OIDC auth, session management, CSRF, API proxy |
The SPA communicates exclusively through the BFF — it never talks to the Porta Admin API directly. The BFF handles Bearer token injection, OIDC token refresh, and security concerns (CSRF, session cookies).
SPA Architecture:
admin-gui/src/client/
├── api/ # Typed API client + 13 React Query domain hook modules
├── components/ # 27 reusable UI components (EntityDataGrid, StatusBadge, etc.)
├── hooks/ # 8 hooks (useAuth, useOrgContext, useTheme, etc.)
├── layouts/ # AppShell, Sidebar, TopBar, Breadcrumbs
├── pages/ # Route page components (Dashboard, Orgs, Apps, Users, etc.)
├── router.tsx # React Router with breadcrumb-enabled routes
└── types.ts # Shared client-side type definitionsApplication Startup Sequence
The application starts via src/index.ts in a strict 7-step sequence:
Fail-fast principle: If any startup step fails (DB connection, Redis connection, config validation), the process logs a fatal error and calls process.exit(1).
Middleware Stack
The Koa middleware stack is assembled in src/server.ts in this precise order:
Key Middleware Details
| Middleware | File | Purpose |
|---|---|---|
| Error Handler | error-handler.ts | Global try/catch, hides internal details for 5xx |
| Request Logger | request-logger.ts | UUID request ID, logs method/url/status/duration |
| Security Headers | security-headers.ts | CSP default-src 'none', X-Frame-Options, HSTS, etc. |
| Metrics | metrics.ts | Prometheus metrics at GET /metrics (optional) |
| Root Page | root-page.ts | Neutral /, /robots.txt, /favicon.ico (no product leakage) |
| Health Check | health.ts | DB + Redis connectivity check at /health |
| Readiness | ready.ts | Readiness probe for container orchestration |
| Admin Auth | admin-auth.ts | JWT Bearer validation for /api/admin/* routes |
| Admin CORS | admin-cors.ts | CORS handling for /api/admin/* (configurable origins) |
| Admin Rate Limiter | admin-rate-limiter.ts | Rate limiting for admin API endpoints |
| Require Permission | require-permission.ts | Granular RBAC permission checks for admin routes |
| Token Rate Limiter | token-rate-limiter.ts | Rate limiting for token endpoints |
| Tenant Resolver | tenant-resolver.ts | Cache-first org lookup from URL slug |
| Client Secret Hash | client-secret-hash.ts | SHA-256 pre-hash for client_secret_post |
| OIDC CORS | oidc-cors.ts | CORS handling for OIDC endpoints |
Multi-Tenancy Model
Porta uses path-based multi-tenancy where each organization gets its own OIDC issuer URL:
https://auth.example.com/{orgSlug}/.well-known/openid-configuration
https://auth.example.com/{orgSlug}/auth
https://auth.example.com/{orgSlug}/tokenThe tenant resolver middleware (src/middleware/tenant-resolver.ts) uses a cache-first strategy:
- Check Redis cache for org by slug
- On miss → query PostgreSQL
- Cache the result in Redis
- Set
ctx.state.organizationfor downstream handlers - Return appropriate HTTP status based on org status:
active→ proceedsuspended→ 403archived→ 410- Not found → pass through (no match)
Graceful Shutdown
On SIGTERM or SIGINT:
- Stop accepting new connections
- Close the HTTP server
- Disconnect Redis
- Close the PostgreSQL pool
- Force exit after 10 seconds if still hanging
Related Documentation
- Data Model — Database schema and entity relationships
- API Design — REST conventions and endpoint structure
- Security — Authentication, crypto, and isolation
- Configuration Reference — All environment variables
- Admin GUI Guide — Product documentation for the Admin GUI