- 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>
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)
- Add
server:admin,server:operator,server:viewerto thecreate_scopecalls for the API resource - 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
- User logs into SaaS at
/platform/via Logto - Token contains:
scope: "platform:admin tenant:manage ... server:admin" - User clicks "View Dashboard" → SSOs into server at
/server/ - Server reads token scope → finds
server:admin→ maps to ADMIN role - 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 7src/main/java/.../config/PublicConfigController.java— add server scopes to the scopes list (so they're requested in tokens)