Skip to content

ÜAuth – zentrale Authentifizierungs- und Tokenschicht

Ausgangslage

  • Minecraft-Clients authentifizieren sich heute nur gegenüber Microsoft/DevAuth. Die Übliche-Server erkennen die Spieler zwar, geben aber kein nach außen verwendbares Token aus.
  • REST-Endpunkte (z. B. /api/profile/personal-totem) erwarten Dashboard-JWTs. Ein Minecraft-Client kann diese nicht erzeugen; jede Mod müsste eine Web-Login-Logik kopieren.
  • Verschiedene Mods/Tools (Totem, Editor-Client, zukünftige QoL-Mods) duplicieren HTTP-Auth-Code oder meiden die APIs ganz.

Ziele

  1. Einheitliche JWT-Ausstellung für alle Übliche-Dienste (Minecraft-Mods, Web, Tools).
  2. Token-Laufzeit, Scopes und Widerruf zentral steuern.
  3. Zero-Login im Client: beim Join erhält der Spieler automatisch ein gültiges Token.
  4. Optional: Weiterverwendung desselben Tokens im Browser (z. B. Profile-Seite per Link öffnen und bereits eingeloggt sein).

Anforderungen & Randbedingungen

  • Issuer: neuer Auth-Service („ÜAuth“) innerhalb des Plattform-Stacks, zuständig für Signatur/Validierung.
  • Tokenformat: JWT (RS256), Claims mindestens sub (User UUID), usr (name), scopes, iat, exp.
  • Scopes: granular (z. B. totem:write, profile:read, inventory:manage) damit Mods nur benötigte Rechte erhalten.
  • Lebensdauer: kurzlebige Access Tokens (z. B. 30 min) + optional Refresh Token (24 h) für Clients, die nicht jedes Mal joinen können.
  • Transport: HTTPS, Authorization: Bearer <jwt>.
  • Backwards-Kompatibilität: dashboard-JWTs können weiterhin akzeptiert werden, solange Signatur/Issuer stimmt.

Architekturüberblick

Komponenten

  1. ÜAuth Service
    • REST-Endpunkte:
      • POST /auth/session/minecraft → nimmt mcUuid, nonce, signature und stellt Access/Refresh aus.
      • POST /auth/token → regulärer OAuth2-like Refresh.
      • GET /.well-known/jwks.json → Schlüsselverteilung.
    • Speichert ausgehändigte Tokens (für Widerruf) und verwaltet Scope-Mapping.
  2. Minecraft-Server Hook
    • Beim erfolgreichen Login erzeugt er ein Kurzzeit-Nonce (z. B. 60 s gültig), signiert mit Server-Key.
    • Sendet Nonce + PlayerUUID zum Client über Custom Payload.
  3. Client Auth Library (Fabric/Forge)
    • Empfangt Nonce, ruft POST /auth/session/minecraft auf, gibt Nonce + eigene Microsoft Session Signatur weiter.
    • Cachet Access/Refresh Token (verschlüsselt in ~/.uebliche/tokens.json).
    • Stellt Utilitys für HTTP-Requests bereit (z. B. AuthorizedHttpClient#get(path, scope)).
  4. Verbrauchende Mods
    • Registrieren benötigte Scopes beim Start.
    • Nutzen Library, kein eigener Token- oder Upload-Code notwendig.

Flows

  1. Minecraft Join
    1. Spieler verbindet sich mit Übliche-Server → AuthHook erstellt Nonce.
    2. Client empfängt Nonce + Endpoint-URL.
    3. Client ruft POST /auth/session/minecraft mit Payload { uuid, nonce, ms_sign, requested_scopes }.
    4. ÜAuth validiert Nonce (von Server signiert) + Microsoft Signatur, stellt JWT + Refresh aus.
    5. Client informiert Mods, dass Token verfügbar ist.
  2. Web Single-Sign-On (optional)
    • Mod öffnet Browser mit https://uebliche.net/profile?token=<jwt>; Website akzeptiert Token, setzt eigenes Cookie.
  3. Refresh
    • Client ruft POST /auth/token mit Refresh Token, erhält neues Access Token ohne erneuten Join.

Änderungen im Code

Server

  • Neuer Dienst (Spring/Quarkus o. ä.) oder Erweiterung im vorhandenen Platform-Service.
  • Konfiguration für JWKS/Keys, Scopes, TTL, Rate Limits.
  • Minecraft-Server Modul, das Nonces ausstellt (z. B. AuthHandshakeListener):
    java
    record NoncePayload(UUID playerId, Instant issuedAt, byte[] signature) {}

Client

  • Neues Modul mods/common-auth (Gradle Subproject) mit:
    • AuthManager (Token State Machine).
    • HttpClient mit Auto-Retry und Scope-Prüfung.
    • Fabric/Forge Hooks (ClientPlayNetworking) zum Empfang des Nonce-Payloads.
  • Totem-Mod ersetzt direkten Hinweis auf Webprofil:
    • Wenn Token vorhanden → In-Game-UI lädt/aktualisiert Totem via API.
    • „Im Browser öffnen“ Button hängt JWT als Query an, sodass Webseite schon eingeloggt ist.

Fahrplan

  1. PoC ÜAuth Service
    • Minimal: In-Memory Nonce Store, statischer Key, simple scope-liste.
    • Endpunkt POST /auth/session/minecraft + JWKS.
  2. Minecraft-Server Hook
    • Custom Payload uebliche:auth_nonce.
  3. Auth Client Library
    • Token-Anfrage, Storage, HTTP-Helper.
  4. Totem Integration
    • UI + Uploads über neues Token.
  5. Rollout auf weitere Mods
    • Editor-Client, Monitoring, ggf. Dev-Tools.
  6. Production Hardening
    • Key-Rotation, Revocation-List, zentraler Audit-Log.

Konkreter Implementierungsplan (Iteration 1)

SchrittTeilDetails
1Server: Nonce-Payload- Neues Paket net.uebliche.features.auth.handshake.
- Listener auf PlayerLoginEvent generiert AuthNonce (UUID nonceId, Instant issuedAt, byte[] signature).
- Überträgt Payload via übliche:auth/nonce (Minestom Custom Channel).
- Signatur = HMAC256(nonceId + playerUuid + issuedAt, JWT_SECRET).
2Server: REST-Endpoint- POST /auth/session/minecraft (Javalin Route unter AuthService).
- Request { "playerId": "<uuid>", "nonceId": "<uuid>", "signature": "<base64>", "scopes": ["totem:write"] }.
- Prüft Nonce (existiert, max 60 s alt, nicht verbraucht).
- Stellt Access (30 min) + Refresh (24 h) aus (AuthToken Sammlung wiederverwenden, tokenType=MCAUTH).
- Response { accessToken, expiresIn, refreshToken, refreshExpiresIn }.
3Client-Library (Fabric)- neues Modul mods/lib-auth mit Singletons AuthState, AuthHttpClient.
- Packet Handler auf übliche:auth/nonce: ruft HTTPS Endpoint auf, speichert Tokens unter %AppData%/.uebliche/tokens.json (verschlüsselt mit Windows DPAPI / SecretKeySpec).
- Exponiert AuthState.requireScope("totem:write") → sorgt dafür, dass Access vorhanden ist (ggf. refresh).
4Totem-Mod Integration- beim Start AuthState.onAvailable(token -> personalTotemClient.setAuthorization(token)).
- Upload UI (nachgelagert) nutzt Library statt Browser.
5Fallback- Falls Token nicht beschaffbar (z. B. Offline), UI zeigt Hinweis + weiterhin Browser-Link.

Datenmodell-Erweiterungen

  • AuthToken erhält Feld origin (DASHBOARD, MC_SESSION) und scopes.
  • Mongo-Index (userId, origin, scopesHash).
  • Neue Collection AuthNonce (TTL 2 Minuten) oder Reuse SignInCode mit speziellem Typ.

Sicherheit

  • Nonces einmalig, expire nach 60 s.
  • Server signiert Nonce → Client kann nicht selbst Nonce bauen.
  • HTTPS erzwingen (dev/staging: env-Flag zum Zulassen von http://localhost).
  • Refresh Token verschlüsselt abgelegt; bei Verlust AuthService.revokeAll(userId).

Offene Punkte

  • Key-Verteilung für Mods → mod-template erhält auth Gradle dependency + env var UEB_AUTH_ENDPOINT.
  • Browser-SSO: separate Route GET /auth/web-login?token=... (optional in Iteration 2).
  • Forge-Port: analoger Packet-Handler in loader-forge.

Mit dieser Basis können alle Übliche-Mods denselben JWT verwenden; spätere Erweiterungen (Web SSO, externe Tools) profitieren ebenfalls. Bitte Feedback, bevor ich mit Implementierung von Schritt 1 beginne.