-
Notifications
You must be signed in to change notification settings - Fork 25
Description
Summary
Clean up router logic after recent changes consolidating routes under /tenants/:tenantID. The current structure has historical artifacts that no longer make sense.
Problem
The current auth model creates confusion in route registration:
// Current route groupings in router.go
nonTenantRoutes // Admin-only, no :tenantID
tenantUpsertRoute // Admin-only, but HAS :tenantID in path
portalRoutes // Admin-only, manually adds RequireTenantMiddleware
tenantAgnosticRoutes // AdminOrTenant - why separate from...
tenantSpecificRoutes // AdminOrTenant - also has tenant in path?Issues:
-
Confusing route groupings - The distinction between
tenantAgnosticRoutesandtenantSpecificRoutesis unclear. Both useAuthScopeAdminOrTenant, both have:tenantIDin path. Historical artifact from when there were two route versions (/:tenantID/destinationsvs/destinationswith JWT). -
Inconsistent tenant middleware - Some routes manually add
RequireTenantMiddleware, others don't. Not clear fromAuthScopewhether a route needs tenant context. -
AuthScope doesn't capture tenant requirement -
AuthScopeAdminon a route with:tenantIDdoesn't tell you if tenant lookup is needed. -
Handlers do their own tenant lookup - Each handler fetches tenant and handles 404 separately.
Goals
- Simplify the mental model for auth
- Centralize tenant lookup in middleware
- Handlers receive validated
*Tenant, not raw ID - Remove confusing route groupings and RouteMode
Proposed Design
Auth Modes (3 total)
const (
AuthPublic AuthMode = "public" // No auth required
AuthTenant AuthMode = "tenant" // Tenant JWT required (admin can also access)
AuthAdmin AuthMode = "admin" // Admin only
)TenantScoped as Contract
type RouteDefinition struct {
Method string
Path string
Handler gin.HandlerFunc
Auth AuthMode // Public, Tenant, Admin
TenantScoped bool // Contract: handler receives *Tenant
Middlewares []gin.HandlerFunc
}TenantScoped: true means middleware injects *Tenant into context, handlers call TenantFromContext(c).
Remove RouteMode
Replace with conditional registration:
routes := baseRoutes
if cfg.PortalEnabled() {
routes = append(routes, portalRoutes...)
}Simplified Route Registration
routes := []RouteDefinition{
{Path: "/healthz", Auth: AuthPublic, TenantScoped: false},
{Path: "/topics", Auth: AuthTenant, TenantScoped: false},
{Path: "/tenants", Auth: AuthAdmin, TenantScoped: false},
{Path: "/tenants/:tenantID", Auth: AuthAdmin, TenantScoped: true},
{Path: "/tenants/:tenantID/destinations", Auth: AuthTenant, TenantScoped: true},
}Each route is self-describing - no confusing groupings.
Prerequisites
Before refactoring, verify test coverage for auth at the API level:
- API key auth (valid, invalid, missing)
- JWT auth (valid, invalid, expired, wrong tenant)
- Tenant not found scenarios
If coverage is weak, add tests first.
Full spec: .ralph/specs/auth-refactor.md
Metadata
Metadata
Assignees
Labels
Type
Projects
Status