# 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-`, never username. `GET /api/v1/users?limit=100` → list; `GET /api/v1/users/` → 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/` 2FA variants all 404; the dashboard UI only offers profile self-service enrollment). Consequence: TOTP seeds not captured at enrollment are unrecoverable without the founder. - 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 ` → 302 to `https://my.knownelement.com/openid/interaction/` (Cloudron runs a node-oidc-provider at `/openid`). Cookies matter — keep a cookie jar. 2. `POST /openid/interaction//login` with JSON `{"username": "", "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-@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 " Cloudron" totp_seed `) at enrollment — there is no admin reset and no recovery path. - Policy RULED (founder, 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: founder 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)