Files
KNELAgentIdentityProvisioning/skills/agent-provisioning/references/cloudron.md
T
mrcharles 0076b4f941 docs: reachableceo wording sweep per 2026-09-09 direct order
House style: the principal identity is named (reachableceo), never
'the founder'. No behavior change.

https://projects.knownelement.com/issues/942
2026-09-09 12:43:23 -05:00

63 lines
3.1 KiB
Markdown

# Cloudron admin API + OIDC (verified 2026-09-08)
## Instance
- Dashboard: `https://my.knownelement.com` (admin surface; this host also
fronts the org's public vhosts — it is NOT the tailscale-only control box).
- API token: vault item `creds/cloudron`, password field, 64 chars, service
user `api-token`. Verified: reads full user directory.
## Routes (this is a newer Cloudron — older route knowledge may not apply)
- Users are addressed by `uid-<uuid>`, never username.
`GET /api/v1/users?limit=100` → list; `GET /api/v1/users/<uid>` → object
(`twoFactorAuthenticationEnabled` is null/absent on objects even when
enforced — the OIDC interaction is the source of truth).
- There is NO `POST /api/v1/login`. Dashboard auth is its own OIDC browser
flow; the SPA bundle (as of 2026-09-08) contains no login route.
- There is NO admin route to reset another user's 2FA (PUT/PATCH/DELETE on
`/users/<uid>` 2FA variants all 404; the dashboard UI only offers profile
self-service enrollment). Consequence: TOTP seeds not captured at
enrollment are unrecoverable without reachableceo.
- Other useful routes seen in the SPA bundle: `/api/v1/tokens`,
`/api/v1/oidc/clients`, `/api/v1/groups`, `/api/v1/eventlog`,
`/api/v1/app_passwords`. Verify behavior at runtime before relying on a
specific payload shape.
## OIDC interaction login (how identity SSO works)
The GLPI/Gitea/Discourse/Redmine SSO flows all redirect here:
1. `GET <app SSO start point>` → 302 to
`https://my.knownelement.com/openid/interaction/<uid>` (Cloudron runs a
node-oidc-provider at `/openid`). Cookies matter — keep a cookie jar.
2. `POST /openid/interaction/<uid>/login` with JSON
`{"username": "<login>", "password": "<unique password>"}`.
- Field name is **`username`** — `login` returns
`"A username must be non-empty string"` (400).
- Success → `{"redirectTo": "..."}` (or
`{"twoFactorRequired":true,"totpRequired":true}` if 2FA is enabled).
- Wrong credentials → 401 `{"status":"Unauthorized","message":"Username
and password does not match"}`.
3. `GET` the `redirectTo` (same cookie jar) → completes at the app.
Email-style usernames work (`tsgstaff-coo@turnsys.com`); bare usernames also
exist (`coo`). Identity emails follow `tsgstaff-<login>@turnsys.com`.
## 2FA
- TOTP enforced per user at the interaction step
(`twoFactorRequired`/`totpRequired` in the login response).
- Enrollment is profile self-service ONLY. Capture the base32 seed into the
vault (`sm setfield "<login> Cloudron" totp_seed <seed>`) at enrollment —
there is no admin reset and no recovery path.
- Policy RULED (reachableceo, 2026-09-08): TOTP seeds MUST be stored in Bitwarden.
Enroll 2FA only when the seed is being captured to the vault item in the
same step. Legacy identities whose seeds were never captured (the whole
August batch) are reset-on-sight candidates: reachableceo clears 2FA or hands
over the seed, then re-enroll with capture.
---
**Records:** Redmine #942 — https://projects.knownelement.com/issues/942 · Discourse docs home: https://community.turnsys.com (skill topic pending admin-key provisioning, tracked on #942)