feat: enforce email as primary user identity in SaaS mode
All users in SaaS mode must have an email address. The bootstrap creates the admin user with primaryEmail set to SAAS_ADMIN_EMAIL (defaults to <SAAS_ADMIN_USER>@<PUBLIC_HOST>). This prevents the admin from being locked out when self-service registration (which requires email) is enabled via the Email Connector UI. Documentation updated across all CLAUDE.md files, .env.example, user-manual.md, and installer submodule (README, .env.example, compose). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,7 @@ Idempotent script run inside the Logto container entrypoint. **Clean slate** —
|
||||
3. Create Logto apps (SPA, Traditional Web App with `skipConsent`, M2M with Management API role + server API role)
|
||||
3b. Create API resource scopes (1 platform + 9 tenant + 3 server scopes)
|
||||
4. Create org roles (owner, operator, viewer with API resource scope assignments) + M2M server role (`cameleer-m2m-server` with `server:admin` scope)
|
||||
5. Create admin user (SaaS admin with Logto console access)
|
||||
5. Create admin user (SaaS admin with Logto console access). Email is the primary user identity in SaaS mode — admin email defaults to `<SAAS_ADMIN_USER>@<PUBLIC_HOST>` if `SAAS_ADMIN_EMAIL` is not set.
|
||||
7b. Configure Logto Custom JWT for access tokens (maps org roles -> `roles` claim: owner->server:admin, operator->server:operator, viewer->server:viewer; saas-vendor global role -> server:admin)
|
||||
8. Configure Logto sign-in branding (Cameleer colors `#C6820E`/`#D4941E`, logo from `/platform/logo.svg`)
|
||||
8c. Configure sign-in experience (sign-in only) — sets `signInMode: "SignIn"` with username+password method. Registration is disabled by default; the vendor admin enables it via the Email Connector UI after configuring SMTP delivery.
|
||||
|
||||
@@ -27,6 +27,9 @@ API_RESOURCE_NAME="Cameleer SaaS API"
|
||||
# Users (configurable via env vars)
|
||||
SAAS_ADMIN_USER="${SAAS_ADMIN_USER:-admin}"
|
||||
SAAS_ADMIN_PASS="${SAAS_ADMIN_PASS:-admin}"
|
||||
# Admin email: use provided value, or derive from username@host.
|
||||
# SaaS enforces email as the user identity — admin must have one.
|
||||
SAAS_ADMIN_EMAIL="${SAAS_ADMIN_EMAIL:-${SAAS_ADMIN_USER}@${PUBLIC_HOST:-localhost}}"
|
||||
|
||||
# No server config — servers are provisioned dynamically by the admin console
|
||||
|
||||
@@ -394,11 +397,12 @@ ADMIN_USER_ID=$(api_get "/api/users?search=$SAAS_ADMIN_USER" | jq -r ".[] | sele
|
||||
if [ -n "$ADMIN_USER_ID" ]; then
|
||||
log "Platform owner exists: $ADMIN_USER_ID"
|
||||
else
|
||||
log "Creating platform owner '$SAAS_ADMIN_USER'..."
|
||||
log "Creating platform owner '$SAAS_ADMIN_USER' (email: $SAAS_ADMIN_EMAIL)..."
|
||||
ADMIN_RESPONSE=$(api_post "/api/users" "{
|
||||
\"username\": \"$SAAS_ADMIN_USER\",
|
||||
\"password\": \"$SAAS_ADMIN_PASS\",
|
||||
\"name\": \"Platform Owner\"
|
||||
\"name\": \"Platform Owner\",
|
||||
\"primaryEmail\": \"$SAAS_ADMIN_EMAIL\"
|
||||
}")
|
||||
ADMIN_USER_ID=$(echo "$ADMIN_RESPONSE" | jq -r '.id')
|
||||
log "Created platform owner: $ADMIN_USER_ID"
|
||||
|
||||
Reference in New Issue
Block a user