From d12071df04787e00c189b6d4e940280a7b9b7889 Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Wed, 24 Jun 2026 22:34:47 +0200 Subject: [PATCH] =?UTF-8?q?fix(mc):=20ONLINE=5FMODE=3Dtrue=20=E2=80=94=20a?= =?UTF-8?q?uthlib-injector=20needs=20online=20handshake=20for=20skins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit online-mode=false made the server skip the online-auth handshake entirely, so authlib-injector never validated sessions against Drasl: players got offline-hash UUIDs and no skin textures (everyone Steve). authlib-injector's whole purpose is to redirect the *online* handshake from Mojang to Drasl, so online-mode must be true; only the 1.21+ secure profile stays off (ENFORCE_SECURE_PROFILE=false + Drasl SignPublicKeys=false). Correct the conflation in CLAUDE.md and plan/05-minecraft.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 10 +++++++++- docker-compose.yml | 9 +++++++-- plan/05-minecraft.md | 15 ++++++++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 70a498a..1518eea 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,7 +35,7 @@ Internet ── host nginx (TLS, LE certs, HSTS) ──► caddy (127.0.0.1:8880 distribution.${BASE} ─► static site from ANOTHER repo (DISTRIBUTION_WEB_ROOT) minecraft :25565 (+ 24454/udp Simple Voice Chat) - └ ONLINE_MODE=false, -javaagent authlib-injector → http://auth.${BASE_DOMAIN}/authlib-injector + └ ONLINE_MODE=true (validated against Drasl, NOT offline), -javaagent authlib-injector → http://auth.${BASE_DOMAIN}/authlib-injector └ mods from ./server-mods volume (/mods, REMOVE_OLD_MODS) — see plan/04-mods.md mc-backup ── RCON → minecraft (6h interval, prune 14d, world-only) ``` @@ -67,6 +67,14 @@ via the `deploy` skill. - Drasl: `SignPublicKeys = false` - Linked. Drasl docs: *"Mixed authentication does not work with `SignPublicKeys = true` on Minecraft 1.21+."* +- **This is the ONLY auth flag that goes off. `ONLINE_MODE` stays TRUE** — see + next gotcha. Do not conflate "secure profile off" with "offline mode". + +### ONLINE_MODE must be TRUE (authlib-injector ≠ offline) +authlib-injector redirects the server's normal **online**-auth handshake from +Mojang to Drasl. `ONLINE_MODE=FALSE` skips that handshake → offline-hash UUIDs, +no Drasl session validation, and **no skins** (everyone joins but everyone is +Steve; `usercache.json` shows offline-hash UUIDs). Keep `ONLINE_MODE=TRUE`. ### authlib-injector JVM agent - Syntax: `-javaagent:/extras/authlib-injector.jar=` diff --git a/docker-compose.yml b/docker-compose.yml index cbb2813..09dcbfc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,8 +58,13 @@ services: USE_AIKAR_FLAGS: "TRUE" JVM_XX_OPTS: "-XX:+UseG1GC" - # ── Auth: offline mode + authlib-injector pointing at Drasl ─ - ONLINE_MODE: "FALSE" + # ── Auth: ONLINE mode validated against Drasl via authlib-injector ─ + # MUST be true: authlib-injector redirects the normal online-auth + # handshake from Mojang to Drasl. online-mode=false skips the handshake + # entirely -> offline UUIDs, no session validation, NO SKINS for anyone. + # Secure-profile is the part that must stay off on 1.21+ (see + # ENFORCE_SECURE_PROFILE + Drasl SignPublicKeys=false), NOT online-mode. + ONLINE_MODE: "TRUE" # Resolves over mcnet to caddy (alias auth.${BASE_DOMAIN}) -> drasl. JVM_OPTS: "-javaagent:/extras/authlib-injector.jar=https://auth.${BASE_DOMAIN}/authlib-injector" diff --git a/plan/05-minecraft.md b/plan/05-minecraft.md index 69c5f04..da9c834 100644 --- a/plan/05-minecraft.md +++ b/plan/05-minecraft.md @@ -25,21 +25,30 @@ mirrors `/mods` into `/data/mods` and prunes removed ones (`REMOVE_OLD_MODS`). ## Auth / config ``` -ONLINE_MODE=FALSE +ONLINE_MODE=TRUE ENFORCE_SECURE_PROFILE=FALSE # pairs with drasl SignPublicKeys=false JVM_OPTS=-javaagent:/extras/authlib-injector.jar=http://auth.${BASE_DOMAIN}/authlib-injector ``` authlib URL uses the `auth` subdomain; resolves internally via the caddy alias. (Server still needs the agent even though Fjord clients have it built in.) +**`ONLINE_MODE` MUST be true.** authlib-injector works by redirecting the +server's normal online-auth handshake from Mojang to Drasl. With +`ONLINE_MODE=FALSE` the server skips that handshake entirely → players get +offline-hash UUIDs, no session validation, and **no skins** (the server never +fetches textures from Drasl). The thing that must stay *off* for 1.21+ is the +**secure profile** (`ENFORCE_SECURE_PROFILE=FALSE` + Drasl `SignPublicKeys=false`), +not online-mode. Symptom of getting this wrong: everyone can join but everyone is +Steve, and `usercache.json` shows offline-hash UUIDs. + Memory: `INIT_MEMORY 4G`, `MAX_MEMORY 10G`, `USE_AIKAR_FLAGS TRUE`. RCON enabled for mc-backup. ## Server operators (OP) **Do NOT use the itzg `OPS` env var.** It resolves usernames to UUIDs via a -Mojang lookup, but this server is `ONLINE_MODE=FALSE` with Drasl auth — Drasl -assigns its own UUIDs (not Mojang, not the offline-hash). A Mojang-resolved UUID +Mojang lookup, but this server is `ONLINE_MODE=TRUE` validated against Drasl — +Drasl assigns its own UUIDs (not Mojang, not the offline-hash). A Mojang-resolved UUID would not match the player's real session UUID, so the op entry would be inert (and could clobber a correct `ops.json` on reboot).