docs(drasl): record admin bootstrap + config-key/CORS/NMSR gotchas

Capture what this session learned the hard way, in plan/03-drasl.md and CLAUDE.md:

- Correct admin key is DefaultAdmins (not DefaultAdminUsernames); wrong/unknown
  keys are silently ignored by drasl (logged as "unknown config option").
- CORSAllowOrigins must be top-level, before any [Section], or it's ignored.
- First-admin bootstrap under invite mode is a chicken-egg → temp-flip
  RequireInvite=false, register, revert.
- NMSR needs the auth. host-gateway pin + https mojank endpoints or avatars
  render the default skin (cross-ref plan/19-routes.md).
- Fix the stale example config and mark the admin-bootstrap task done.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 21:20:54 +02:00
parent de1ac2ee17
commit c233b1bfbc
2 changed files with 31 additions and 3 deletions

View File

@@ -19,10 +19,13 @@ Config is **TOML only** (no env var support). So `config.toml` is rendered from
BaseURL = "https://auth.${BASE_DOMAIN}" # public scheme is HTTPS (nginx TLS)
Domain = "auth.${BASE_DOMAIN}"
ListenAddress = "0.0.0.0:25585" # internal; Caddy proxies
DefaultAdminUsernames = ["admin"]
DefaultAdmins = ["admin"] # NOT DefaultAdminUsernames (see gotchas)
AllowPasswordLogin = true
# Top-level — NOT under any [Section] (see gotchas).
CORSAllowOrigins = ["https://${BASE_DOMAIN}"]
[ApplicationOwner]
# ...
@@ -38,6 +41,28 @@ AllowPasswordLogin = true
`http://auth.ulicraft.net/authlib-injector`. Must match on server and client.
Network alias makes this identical inside/outside the stack.
- **`Domain` affects skins** — if wrong, authlib clients may not see skins.
- **Config keys are validated loosely — wrong keys are silently ignored** (drasl
logs `Warning: unknown config option <key>` and moves on). Two that bit us:
- Admin list key is **`DefaultAdmins`** (top-level), NOT `DefaultAdminUsernames`
(that key never existed → no admin → admin-only routes like `GET /players`
return 403).
- **`CORSAllowOrigins` must be top-level**, before any `[Section]`. Placed after
a table header it parses as `<table>.CORSAllowOrigins`, is ignored, and the
API serves no CORS headers → landing register/account browser calls blocked.
- `RateLimit.Burst` is valid in drasl master but warns on `unmojang/drasl:latest`
(image lags) — harmless.
- **First-admin bootstrap with invite mode on is a chicken-egg.** `DefaultAdmins`
only promotes the account at startup reconciliation, and `POST /drasl/api/v2/users`
is invite-gated (admins do NOT bypass the *register* endpoint). To create the
first admin: temporarily set `RequireInvite = false` in the rendered config,
`docker compose restart drasl`, `POST /users` to register `admin`, then revert +
restart (always trap-revert). API recap: `POST /login {username,password}`
`{apiToken}`; admin-only `GET /players` with `Authorization: Bearer <token>`.
- **NMSR avatars need https + a host-gateway pin** (see `plan/19-routes.md`).
Drasl's profile embeds **https** skin URLs (BaseURL is https). NMSR reaches
those via `extra_hosts: auth.${BASE_DOMAIN}:host-gateway` (host nginx :443, real
LE cert) with https mojank endpoints. Without it the skin fetch Connect-fails to
caddy:443 and every avatar renders the DEFAULT skin.
## Tasks
@@ -47,6 +72,7 @@ AllowPasswordLogin = true
- [ ] Wire `render-config.sh``drasl/config/config.toml` (gitignored)
- [ ] Remove drasl host port from compose (internal only)
- [ ] Update compose: drasl on `mcnet`, no `25585:25585` publish
- [ ] Bootstrap admin account on first run; create guest accounts
- [x] Bootstrap admin account (`admin`, done 2026-06-10 via invite-flip; creds in
cochi `.env` for the mc-status roster). Create guest accounts as needed.
- [ ] Verify authlib endpoint responds through Caddy
- [ ] Future: re-add `[[RegistrationOIDC]]` Keycloak block + secret file