Skip to content

Instantly share code, notes, and snippets.

@sanasol
Created January 19, 2026 18:46
Show Gist options
  • Select an option

  • Save sanasol/bafe0edecda42be0f310e39f9b8e0d27 to your computer and use it in GitHub Desktop.

Select an option

Save sanasol/bafe0edecda42be0f310e39f9b8e0d27 to your computer and use it in GitHub Desktop.

Hytale F2P Setup - Project Summary

Overview

This project enables running a complete free-to-play Hytale setup with custom authentication, bypassing the official Hytale authentication servers. It consists of three interconnected repositories that work together.

Repositories

Repository Description Status
hytale-auth-server Authentication server handling JWT signing Ready for GitHub
hytale-server-docker Dedicated game server Docker image Updated
Hytale-F2P Game launcher with binary patching Updated

What Was Accomplished

1. Binary Patching System

Problem: Hytale client and server binaries hardcode hytale.com for authentication.

Solution: Binary patching to replace domain at runtime.

Client Patcher (f2p/backend/utils/clientPatcher.js)

  • Patches HytaleClient.dll (.NET binary)
  • Uses UTF-16LE encoding (Windows .NET strings)
  • Handles two string formats:
    • Standard null-terminated: h\x00y\x00t\x00a\x00l\x00e\x00.\x00c\x00o\x00m\x00
    • Length-prefixed: h\x00y\x00t\x00a\x00l\x00e\x00.\x00c\x00o\x00m\x89 (metadata byte instead of null)
  • Finds 4 occurrences in the binary
  • Critical fix: macOS code signing must happen AFTER patching (not before)

Server Patcher (hytale-server-docker/scripts/patch-server.sh)

  • Patches HytaleServer.jar (Java binary)
  • Uses UTF-8 encoding (Java strings)
  • Bash script using unzip, perl, zip
  • Creates .patched_custom flag file to avoid re-patching

2. Authentication Server (hytale-auth-server)

Purpose: Handle all authentication requests from game client and dedicated servers.

Features

  • Ed25519 JWT signing with persisted key pairs
  • JWKS endpoint (/.well-known/jwks.json) for signature verification
  • mTLS certificate binding (cnf.x5t#S256 claim)
  • Cosmetics extraction from Assets.zip
  • User data persistence (skins saved by username)

Endpoints Implemented

Endpoint Purpose
/.well-known/jwks.json JWT public key for verification
/game-session/new Create new session (launcher/server)
/game-session/child Create child session
/game-session/refresh Refresh existing session
/server-join/auth-grant Authorization grant for server connection
/server-join/auth-token Token exchange with cert binding
/my-account/game-profile Get user profile
/my-account/cosmetics Get unlocked cosmetics
/my-account/skin Save skin preferences
/my-account/get-profiles Get all profiles

Files Created

  • server.js - Main server code
  • Dockerfile - Docker build configuration
  • package.json - Node.js dependencies
  • compose.yaml - Production config with Traefik (HTTPS)
  • compose.simple.yaml - Local development (HTTP)
  • README.md - Documentation
  • LICENSE - MIT License
  • .gitignore - Git ignore rules
  • assets/.gitkeep - Placeholder for Assets.zip

3. Configuration Centralization

Problem: Domain sanasol.ws was hardcoded in multiple places.

Solution: Centralized configuration with environment variable support.

Config System (f2p/backend/core/config.js)

const DEFAULT_AUTH_DOMAIN = 'sanasol.ws';

function getAuthDomain() {
  // Priority: env var > config file > default
  if (process.env.HYTALE_AUTH_DOMAIN) return process.env.HYTALE_AUTH_DOMAIN;
  const config = loadConfig();
  if (config.authDomain) return config.authDomain;
  return DEFAULT_AUTH_DOMAIN;
}

Environment Variables

Variable Default Used By
HYTALE_AUTH_DOMAIN sanasol.ws All components
HYTALE_PATCH_SERVER false Docker server
HYTALE_AUTO_FETCH_TOKENS false Docker server
HYTALE_AUTH_SERVER https://sessions.sanasol.ws Docker server

4. Domain Constraint

Requirement: Custom domain must be exactly 10 characters (same as hytale.com).

Reason: Binary patching replaces bytes in-place. Different length would corrupt the binary.

Examples: sanasol.ws, example.co, myserver.x

5. Public Test Infrastructure

Public Auth Server

  • Domain: sanasol.ws
  • Endpoints: sessions.sanasol.ws, account-data.sanasol.ws, telemetry.sanasol.ws
  • All cosmetics unlocked
  • Cosmetics saved by username

Public Game Server

  • Address: ht.vboro.de:5720
  • Uses sanasol.ws auth server

Pre-built Release

6. Documentation Updates

hytale-auth-server README

  • Public test server section
  • Quick test instructions (download + connect)
  • Requirements for own server
  • Complete setup guide
  • Troubleshooting section
  • Cross-links to related projects

hytale-server-docker README

  • Custom Auth Server Support section
  • Public Test Server (Default) section
  • Quick Start (Using Public Test Server)
  • Complete Setup (Own Auth Server)
  • Cross-links to related projects

Technical Details

macOS Code Signing Fix

Problem: Game crashed after patching, then reverted to hytale.com on restart.

Root Cause: macOS was re-signing the binary BEFORE patching, then the patched binary had an invalid signature.

Fix (gameLauncher.js):

// Order: fetch tokens → patch → sign (macOS) → launch
const authDomain = getAuthDomain();
if (clientPatcher) {
  await clientPatcher.ensureClientPatched(gameLatest, ...);
}

// macOS: Sign binaries AFTER patching
if (process.platform === 'darwin') {
  // codesign --force --deep --sign - <binary>
}

UTF-16LE String Format Discovery

Problem: Patcher found 3 occurrences but game still used hytale.com.

Investigation: Hex dump revealed 4th occurrence had different format:

Standard:        h 00 y 00 t 00 a 00 l 00 e 00 . 00 c 00 o 00 m 00
Length-prefixed: h 00 y 00 t 00 a 00 l 00 e 00 . 00 c 00 o 00 m 89

Fix: Check only first byte of last character, preserve metadata byte:

const lastCharFirstByte = result[lastCharPos];
if (lastCharFirstByte === oldLastCharByte) {
  newUtf16NoLast.copy(result, pos);
  result[lastCharPos] = newLastCharByte;
  // Preserves 0x00 or 0x89 in second byte position
}

Security Considerations

Current Limitations

  • No password authentication - anyone can use any username
  • Shared profiles - same username = same cosmetic profile
  • For testing purposes only

Potential Fix: Claim Token System

  1. First login → server generates secret claim token
  2. Token stored locally on client
  3. Future skin saves require token
  4. Without token → fresh profile (can't modify existing)

Not yet implemented - would require changes to both server and launcher.


Git Repositories Status

hytale-auth-server

cd /Users/sanasol/code/pterodactyl-hytale/hytale-auth-server
git remote -v
# origin  git@github.com:sanasol/hytale-auth-server.git

git log --oneline
# 24535e5 Add disclaimer about shared usernames
# ca9a5f5 Add cosmetics info to public test server section
# 8405907 Add pre-built release and public game server links
# f70c5d9 Add public test server documentation
# 3b94462 Initial commit: Hytale Auth Server

# To push:
git push -u origin master

hytale-server-docker

cd /Users/sanasol/code/pterodactyl-hytale/hytale-server-docker
git remote -v
# origin  git@github.com:sanasol/hytale-server-docker.git

# Recent commits ready to push:
git push

Quick Start Guide

Option 1: Use Public Test Server (No Setup)

  1. Download Hytale-F2P v2.0.4-auth-sanasol.ws
  2. Launch and connect to ht.vboro.de:5720

Option 2: Run Own Game Server (Using Public Auth)

git clone https://github.com/sanasol/hytale-server-docker.git
cd hytale-server-docker
docker compose build
docker compose up -d

Option 3: Complete Self-Hosted Setup

  1. Set up auth server with custom 10-char domain
  2. Configure DNS records
  3. Start auth server with Traefik
  4. Start game server with custom domain
  5. Build launcher with custom domain

File Locations

Key Files Modified/Created

Path Description
/f2p/backend/core/config.js Centralized auth domain configuration
/f2p/backend/utils/clientPatcher.js Client binary patcher (UTF-16LE)
/f2p/backend/managers/gameLauncher.js Game launch with proper patch→sign order
/hytale-server-docker/scripts/patch-server.sh Server JAR patcher (UTF-8)
/hytale-server-docker/README.md Updated with custom auth docs
/hytale-auth-server/* Complete auth server package

Summary

Successfully created a complete Hytale F2P infrastructure:

  1. Binary patching for both client (.NET/UTF-16LE) and server (Java/UTF-8)
  2. Custom auth server with Ed25519 JWT signing and all required endpoints
  3. Centralized configuration with environment variable support
  4. Public test infrastructure at sanasol.ws with game server at ht.vboro.de:5720
  5. Pre-built releases for immediate testing
  6. Comprehensive documentation with cross-links between all repositories

All components are designed to work together out of the box with default sanasol.ws configuration, while supporting custom domains for self-hosted setups.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment