feat: configure Logto Custom JWT and update server OIDC rolesClaim
- Change rolesClaim from "scope" to "roles" to match the custom claim injected by the Logto Custom JWT script - Add Phase 7b: configure Logto Custom JWT for access tokens that maps org roles (admin→server:admin, member→server:viewer) and global roles (platform-admin→server:admin) into a standard "roles" claim - Add additionalScopes field to OIDC config Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -554,8 +554,9 @@ if [ "$SERVER_HEALTHY" = "yes" ] && [ -n "$TRAD_SECRET" ]; then
|
|||||||
\"autoSignup\": true,
|
\"autoSignup\": true,
|
||||||
\"defaultRoles\": [\"VIEWER\"],
|
\"defaultRoles\": [\"VIEWER\"],
|
||||||
\"displayNameClaim\": \"name\",
|
\"displayNameClaim\": \"name\",
|
||||||
\"rolesClaim\": \"scope\",
|
\"rolesClaim\": \"roles\",
|
||||||
\"audience\": \"$API_RESOURCE_INDICATOR\"
|
\"audience\": \"$API_RESOURCE_INDICATOR\",
|
||||||
|
\"additionalScopes\": []
|
||||||
}")
|
}")
|
||||||
log "OIDC config response: $(echo "$OIDC_RESPONSE" | head -c 200)"
|
log "OIDC config response: $(echo "$OIDC_RESPONSE" | head -c 200)"
|
||||||
log "cameleer3-server OIDC configured."
|
log "cameleer3-server OIDC configured."
|
||||||
@@ -566,6 +567,39 @@ else
|
|||||||
log "WARNING: cameleer3-server not available or no Traditional app secret — skipping OIDC config"
|
log "WARNING: cameleer3-server not available or no Traditional app secret — skipping OIDC config"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PHASE 7b: Configure Logto Custom JWT for access tokens
|
||||||
|
# ============================================================
|
||||||
|
# Adds a 'roles' claim to access tokens based on user's org roles and global roles.
|
||||||
|
# This allows the server to extract roles from the access token using rolesClaim: "roles".
|
||||||
|
|
||||||
|
log "Configuring Logto Custom JWT for access tokens..."
|
||||||
|
CUSTOM_JWT_SCRIPT='const getCustomJwtClaims = async ({ token, context, environmentVariables }) => {
|
||||||
|
const roleMap = { admin: "server:admin", member: "server:viewer" };
|
||||||
|
const roles = new Set();
|
||||||
|
if (context?.user?.organizationRoles) {
|
||||||
|
for (const orgRole of context.user.organizationRoles) {
|
||||||
|
const mapped = roleMap[orgRole.roleName];
|
||||||
|
if (mapped) roles.add(mapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (context?.user?.roles) {
|
||||||
|
for (const role of context.user.roles) {
|
||||||
|
if (role.name === "platform-admin") roles.add("server:admin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles.size > 0 ? { roles: [...roles] } : {};
|
||||||
|
};'
|
||||||
|
|
||||||
|
CUSTOM_JWT_PAYLOAD=$(jq -n --arg script "$CUSTOM_JWT_SCRIPT" '{ script: $script }')
|
||||||
|
CUSTOM_JWT_RESPONSE=$(api_put "/api/configs/jwt-customizer/access-token" "$CUSTOM_JWT_PAYLOAD" 2>&1)
|
||||||
|
if echo "$CUSTOM_JWT_RESPONSE" | jq -e '.script' >/dev/null 2>&1; then
|
||||||
|
log "Custom JWT configured for access tokens."
|
||||||
|
else
|
||||||
|
log "WARNING: Custom JWT configuration failed — server OIDC login may fall back to local roles"
|
||||||
|
log "Response: $(echo "$CUSTOM_JWT_RESPONSE" | head -c 200)"
|
||||||
|
fi
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# PHASE 8: Configure sign-in branding
|
# PHASE 8: Configure sign-in branding
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user