Skip to content

Fixes for authlib-injector accounts#2890

Closed
evan-goode wants to merge 4 commits intoMCCTeam:masterfrom
unmojang:evan-goode/fix-yggdrasil
Closed

Fixes for authlib-injector accounts#2890
evan-goode wants to merge 4 commits intoMCCTeam:masterfrom
unmojang:evan-goode/fix-yggdrasil

Conversation

@evan-goode
Copy link
Copy Markdown

This PR includes several fixes for authlib-injector (here called "Yggdrasil" or "Authlib") accounts. For unmojang/drasl#66.

  • Add a new config option, Main.General.AuthServer.AuthlibInjectorAPIPath, to allow specifying the path to the root of the authlib-injector API. Whereas Blessing Skin places their API at /api/yggdrasil, other authlib-injector servers (Drasl, Ely.By) do not, so this change enables compatibility with them.
  • Add docstrings for some AuthServer config options
  • Don't send an invalid ("dummy") profile key signature for authlib-injector accounts; this breaks vanilla Minecraft servers
  • Replace the custom HTTP implementation in DoHTTPSRequest with System.Net.Http.HttpClient, but still respect the configured proxy.
    • Note: I am unsure of this change. According to a comment, the custom HTTP client was used "since we must directly use a TcpClient because of the proxy." But it seems straightforward to pass a custom TcpClient to HttpClient---that's what I did here. It sent the request through my TCP proxy when I tested it. Is this correct?
  • Fetch certificates for authlib-injector accounts if the authlib-injector server has the feature.enable_profile_key flag set

See commit message for more details. I'm a C# amateur, so a thorough review would be appreciated :)

The previous authlib-injector authentication implementation always
assumed that the authlib-injector API location was located at
https://authlibinjectorserver.example.com/api/yggdrasil. Blessing Skin
structures their API like that, but other authlib-injector-compatible
Yggdrasil implementations do not. Per the authlib-injector
specification, the API root can be located at any path, and that path
should be pointed to by the `X-Authlib-Injector-API-Location` header
[1].

With this change, the default AuthlibInjectorAPIPath is kept as
`/api/yggdrasil`, so users will not need to update their config.

See also
unmojang/drasl#66 (comment).

[1] https://github.com/yushijinhun/authlib-injector/wiki/Yggdrasil-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83
Instead of sending an invalid profile key signature, it's better to just
send no signature. If we send an invalid signature, the vanilla server will
throw an error even if `enforce-secure-profile` is `false`.

See also yushijinhun/authlib-injector#266.
The DIY HTTP client had many problems, as is expected when
rolling your own HTTP implementation without following the spec.

Fortunately, we can use SocketsHttpHandler.ConnectCallback to make
HttpClient use our custom TCP client.
Some authlib-injector-compatible authentication servers implement the
POST /player/certificates route used for fetching player certificates.

To comply with the authlib-injector Yggdrasil server specification [1], we
first query the authlib-injector metadata and check for the
`feature.enable_profile_key` flag. If the flag is set, the
authentication server supports the /player/certificates route.

In this case, checking the authlib-injector metadata isn't really
necessary; if the /player/certificates request fails for any reason, we
simply ignore it anyway.

[1] https://github.com/yushijinhun/authlib-injector/wiki/Yggdrasil-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83
@milutinke
Copy link
Copy Markdown
Member

Thanks for the work.
Have you tested this, does it full work?
The code looks fine, other than translations being hard coded, but we can add those in later.

milutinke added a commit to milutinke/Minecraft-Console-Client that referenced this pull request Mar 22, 2026
…asil auth

Re-implements the changes from PR MCCTeam#2890, adapted for the current codebase
which uses System.Text.Json.Nodes and HttpClient instead of the legacy
Json.JSONData and hand-rolled SslStream HTTP client.

Changes:
- Settings.cs: Convert AuthlibServer from struct to class with
  [TomlDoNotInlineObject]; convert Host to a property that parses
  'host:port' syntax; add AuthlibInjectorAPIPath (default '/api/yggdrasil')
  for servers that use a different prefix (e.g. Drasl uses '/authlib-injector');
  add UseHttps (default true) so local/dev auth servers without TLS work.

- ConfigComments.resx: Add descriptive inline comments for the new
  AuthlibServer fields (Host, Port, AuthlibInjectorAPIPath, UseHttps).

- ProtocolHandler.cs: Replace three hardcoded '/api/yggdrasil/...' paths
  with AuthlibInjectorAPIPath-based paths (authenticate, refresh, join).
  Replace hand-rolled TcpClient+SslStream HTTP in DoHTTPSRequest with
  HttpClient+SocketsHttpHandler (ConnectCallback routes through ProxyHandler).
  Add useHttps parameter so HTTP-only auth servers are supported.

- KeyUtils.cs: Add AuthServerSupportsProfileKeys() that fetches the
  authlib-injector metadata endpoint and checks feature.enable_profile_key.
  Update GetNewProfileKeys() to skip key fetch when the auth server does not
  support profile keys; build the cert URL dynamically using AuthlibInjectorAPIPath
  for Yggdrasil; always fetch real certs instead of returning a dummy response.
  Remove MakeDummyResponse() which is no longer needed.

Tested against a local Drasl instance with authlib-injector 1.2.7 on a
1.21.11 Minecraft server — full auth flow (login, profile key fetch, session
join) confirmed working end-to-end.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@milutinke
Copy link
Copy Markdown
Member

I've re-implemented the code in #2963 and tested it. It works.
Thank you for your contribution.
I'll close this PR and merge the new one.

@milutinke milutinke closed this Mar 22, 2026
milutinke added a commit to milutinke/Minecraft-Console-Client that referenced this pull request Mar 22, 2026
…asil auth

Re-implements the changes from PR MCCTeam#2890, adapted for the current codebase
which uses System.Text.Json.Nodes and HttpClient instead of the legacy
Json.JSONData and hand-rolled SslStream HTTP client.

Changes:
- Settings.cs: Convert AuthlibServer from struct to class with
  [TomlDoNotInlineObject]; convert Host to a property that parses
  'host:port' syntax; add AuthlibInjectorAPIPath (default '/api/yggdrasil')
  for servers that use a different prefix (e.g. Drasl uses '/authlib-injector');
  add UseHttps (default true) so local/dev auth servers without TLS work.

- ConfigComments.resx: Add descriptive inline comments for the new
  AuthlibServer fields (Host, Port, AuthlibInjectorAPIPath, UseHttps).

- ProtocolHandler.cs: Replace three hardcoded '/api/yggdrasil/...' paths
  with AuthlibInjectorAPIPath-based paths (authenticate, refresh, join).
  Replace hand-rolled TcpClient+SslStream HTTP in DoHTTPSRequest with
  HttpClient+SocketsHttpHandler (ConnectCallback routes through ProxyHandler).
  Add useHttps parameter so HTTP-only auth servers are supported.

- KeyUtils.cs: Add AuthServerSupportsProfileKeys() that fetches the
  authlib-injector metadata endpoint and checks feature.enable_profile_key.
  Update GetNewProfileKeys() to skip key fetch when the auth server does not
  support profile keys; build the cert URL dynamically using AuthlibInjectorAPIPath
  for Yggdrasil; always fetch real certs instead of returning a dummy response.
  Remove MakeDummyResponse() which is no longer needed.

Tested against a local Drasl instance with authlib-injector 1.2.7 on a
1.21.11 Minecraft server — full auth flow (login, profile key fetch, session
join) confirmed working end-to-end.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants