A lightweight proxy service that converts Yggdrasil API logic into the CustomSkinLoader (CSL) compatible protocol format.
HASkinProxy acts as a compatibility layer between Yggdrasil-compliant authentication services (such as HRPAuth) and Minecraft clients using CustomSkinLoader.
While originally designed for the HA ecosystem (defined in HA-Contract), this proxy forwards standard Yggdrasil API calls. This means it is compatible with any authentication server that implements the Yggdrasil protocol, allowing seamless skin and cape loading without modifying the upstream service.
All interface documents and development specifications are unified in the root directory:
- CustomSkinAPI Compatibility: Fully implements the standard CSL protocol.
- Yggdrasil Integration: Communicates with upstreams via standard Yggdrasil endpoints (
/api/profiles/minecraftand/sessionserver/session/minecraft/profile/{uuid}). - Universal Support: Works with HRPAuth or any other Yggdrasil-compatible server.
- High Performance Caching: Uses
freecachefor in-memory caching of profiles and texture data to reduce upstream load. - Auto-Config Generation: Automatically generates a default
config.yamlon the first run. - Lightweight: Built with the Gin framework for high concurrency and low latency.
- Go 1.20 or higher.
-
Clone the repository:
git clone <repository-url> cd HASkinProxy
-
Build and run:
go run main.go
On the first run, it will generate a
config.yamlin the current directory. -
Configure your upstream: Edit
config.yamlto point to your Yggdrasil-compatible service URL.
The config.yaml file includes the following sections:
server:
listen_addr: ":2702" # Port for the proxy to listen on
public_url: "http://localhost:2702" # Externally reachable base URL, announced in the presence handshake (SDK)
upstream:
base_url: "http://localhost:2778" # Your Yggdrasil service URL (e.g., HRPAuth)
timeout: 10 # Upstream request timeout in seconds
cache:
profile_ttl: 3600 # Profile cache duration (seconds)
texture_ttl: 86400 # Texture cache duration (seconds)
max_size_mb: 256 # Maximum cache size in MB
presence:
enabled: true # Register with HRPAuth via POST /services/presence
name: "HASkinProxy" # Service name in the presence registry
ttl_seconds: 0 # Self-declared lifetime (seconds); <=0 means never expire- GET
/{username}.json: Returns the player's CSL profile (skin/cape hashes). - GET
/textures/{hash}: Returns the raw texture image data. - GET
/customskinloader: CustomSkinLoader setup page (config generator + usage), embedded in the WEBUI Dashboard. - GET
/sdk/haskinproxy.js: Microservice SDK JS, relayed by HRPAuth to the WEBUI (declares the Dashboard menu item). - GET
/health: Simple health check endpoint.
On startup, the proxy performs the presence (bonjour) handshake with HRPAuth (POST /services/presence) and declares the webui-dash frontend area plus its sdk_url. It then registers a relay rule (POST /services/relay) so the CustomSkinLoader page is served through the main service origin. The HRPAuth WEBUI discovers the service and automatically adds a CustomSkinLoader item to the Dashboard sidebar, loading the setup page via {BackendUrl}/customskinloader (relayed to this proxy). Requires server.public_url to be set to an address reachable by HRPAuth.
- Request: Client requests
Player.json. - Lookup: Proxy fetches UUID via
POST /api/profiles/minecraft. - Profile: Proxy fetches Yggdrasil profile via
GET /sessionserver/session/minecraft/profile/{uuid}. - Transform: Proxy extracts texture hashes and formats them into CSL JSON.
- Cache: Result is cached to speed up subsequent requests.
- HRPAuth: https://github.com/CoreMatch/HRPAuth
- HA-Contract: https://github.com/CoreMatch/HA-Contract
- CustomSkinLoader: https://github.com/xfl03/MCCustomSkinLoader
This project is licensed under the GNU Affero General Public License v3.0.