Skip to content

Conversation

evan-goode
Copy link
Contributor

"Mojang auth" (now ironically named) is still in use today by custom authentication servers. We are grateful for node-minecraft-protocol's continued support for it! Some of these custom authentication servers [0][1] support player certificates just like Mojang's API servers do, at the $servicesServer/player/certificates endpoint (when using Mojang's servers, $servicesServer = https://api.minecraftservices.com). The process for fetching player certificates is no different when using a Microsoft account or a Mojang/other account. It works like any other Mojang API route that requires an accessToken. But in node-minecraft-protocol, Microsoft authentication, including certificate fetching, is done in prismarine-auth and certificate fetching isn't implemented for third-party accounts.

This PR copies the certificate fetching logic from prismarine-auth to mojangAuth.js in node-minecraft-protocol to make certificate fetching work with third-party accounts. Certificate fetching can be disabled by setting disableChatSigning: true just like with Microsoft accounts. If certificates fetching fails, a warning is printed and login continues.

An alternative approach to copying would be to export fetchCertificates from prismarine-auth and somehow make it possible to override the servicesServer there. But IMHO the cleaner option is to duplicate the code in node-minecraft-protocol, it's only ~20 lines.

[0] https://github.com/unmojang/drasl
[1] https://ely.by/

Borrows the fetchCertificates implementation from prismarine-auth
@evan-goode evan-goode force-pushed the evan-goode/custom-auth branch from 9b32bb0 to 2080118 Compare July 28, 2025 20:10
@evan-goode
Copy link
Contributor Author

Thanks for the approval. The CI failure seems to be transient and unrelated.

@@ -47,7 +74,7 @@ module.exports = async function (client, options) {

if (options.haveCredentials) {
// make a request to get the case-correct username before connecting.
const cb = function (err, session) {
const cb = async function (err, session) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cb can't be async

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... why not? Everywhere cb is called, the return value is not used, so does it matter whether it returns a Promise or undefined? And cb is already used as a callback at

                yggdrasilClient.auth({
                  user: options.username,
                  pass: options.password,
                  token: clientToken,
                  requestUser: true
                }, cb)

so we do not need to guarantee that auth is complete by the time the outer exported auth function returns, that's what the session event is for.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"cb is used as a callback" is exactly the issue

Callback and promise/async are 2 mutually exclusive options

If you put async keyword on a function, it means some code will await that function wereas a callback is called directly without await

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes it's nice to use async just so you can use await within the function itself, without necessarily using the returned Promise. But I can rewrite this with additional callbacks if you'd like. I think functionally it'd be the same.

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.

3 participants