Files
cameleer-saas/docs/superpowers/specs/2026-04-06-server-role-mapping-design.md
hsiegeln b1c2832245
All checks were successful
CI / build (push) Successful in 40s
CI / docker (push) Successful in 11s
docs: update architecture with bootstrap phases, scopes, branding
- CLAUDE.md: add bootstrap phase listing, document 13 scopes (10
  platform + 3 server), server role mapping via scope claim, admin
  console access, sign-in branding
- Mark server-role-mapping and logto-admin-branding specs as implemented

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:46:39 +02:00

3.1 KiB

Server Role Mapping via Logto Scopes — IMPLEMENTED

Problem

When a Logto user SSOs into the cameleer3-server, they get VIEWER role by default (OIDC auto-signup). There's no automatic mapping between Logto organization roles and server roles. A SaaS admin must manually promote users in the server.

Constraint

SaaS platform roles must NOT map to server roles. A platform:admin is not automatically a server:admin. The two role systems are independent — only server-specific scopes trigger server role assignment.

Solution

Add namespaced server scopes (server:admin, server:operator, server:viewer) to the Logto API resource. Assign them to organization roles. The server reads the scope claim from the JWT and maps to its RBAC roles.

Scopes

New scopes on API resource https://api.cameleer.local:

Scope Server Role Description
server:admin ADMIN Full server access
server:operator OPERATOR Deploy, manage apps
server:viewer VIEWER Read-only observability

Existing SaaS scopes remain unchanged (platform:admin, tenant:manage, etc.).

Organization Role Assignments

Org Role SaaS Scopes (existing) Server Scopes (new)
admin platform:admin, tenant:manage, billing:manage, team:manage, apps:manage, apps:deploy, secrets:manage, observe:read, observe:debug, settings:manage server:admin
member apps:manage, apps:deploy, observe:read, observe:debug server:viewer

Changes

Bootstrap (docker/logto-bootstrap.sh)

  1. Add server:admin, server:operator, server:viewer to the create_scope calls for the API resource
  2. Include them in the org role → API resource scope assignments

SaaS Frontend (ui/src/main.tsx or PublicConfigController)

Add the server scopes to the requested scopes list so Logto includes them in access tokens. The SaaS app ignores them; the server reads them.

Server Team

Update scope-to-role mapping in JwtAuthenticationFilter:

// Before:
if (scopes.contains("admin")) return List.of("ADMIN");
// After:
if (scopes.contains("server:admin")) return List.of("ADMIN");
if (scopes.contains("server:operator")) return List.of("OPERATOR");
if (scopes.contains("server:viewer")) return List.of("VIEWER");

OIDC Config (bootstrap Phase 7)

Set rolesClaim: "scope" in the server OIDC config so the server reads roles from the scope claim:

{
  "rolesClaim": "scope",
  "defaultRoles": ["VIEWER"]
}

Token Flow

  1. User logs into SaaS at /platform/ via Logto
  2. Token contains: scope: "platform:admin tenant:manage ... server:admin"
  3. User clicks "View Dashboard" → SSOs into server at /server/
  4. Server reads token scope → finds server:admin → maps to ADMIN role
  5. User has full admin access in server — no manual promotion

Files to Modify

  • docker/logto-bootstrap.sh — add server scopes, assign to org roles, set rolesClaim in Phase 7
  • src/main/java/.../config/PublicConfigController.java — add server scopes to the scopes list (so they're requested in tokens)