Skip to content

Instantly share code, notes, and snippets.

@astra137
Last active February 4, 2021 09:01
Show Gist options
  • Save astra137/4784ed9748429b01bf28414f9b90ca9c to your computer and use it in GitHub Desktop.
Save astra137/4784ed9748429b01bf28414f9b90ca9c to your computer and use it in GitHub Desktop.
Demo process for getting Minecraft access token with Microsoft Account
// Experiments based on:
// https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/src/client/microsoftAuth.js
const {createServer} = require('http');
const {URL} = require('url');
const fetch = require('node-fetch');
const msal = require('@azure/msal-node');
const XboxLiveAuth = require('@xboxreplay/xboxlive-auth');
const prettyMilliseconds = require('pretty-ms');
const XSTSRelyingParty = 'rp://api.minecraftservices.com/';
const URL_LOGIN_XBOX = 'https://api.minecraftservices.com/authentication/login_with_xbox';
const URL_MC_PROFILE = 'https://api.minecraftservices.com/minecraft/profile';
const USER_AGENT = 'starburn/minecraft-auth-test';
const scopes = ['XboxLive.signin', 'offline_access'];
const pca = new msal.PublicClientApplication({
auth: {
clientId: 'PUT AZURE APP REGISTRATION Application (client) UUID HERE',
authority: 'https://login.microsoftonline.com/consumers'
}
});
async function getAuthorizationTokenWithLocalhost(onURL) {
const requestUrl = await new Promise((resolve, reject) => {
let port;
const server = createServer((request, response) => {
resolve(new URL(request.url, `http://localhost:${port}`));
response.setHeader('Location', 'https://minecraft.net');
response.writeHead(303);
response.end();
server.close();
});
server.listen(null, '127.0.0.1', () => {
port = server.address().port;
pca.getAuthCodeUrl({
redirectUri: `http://localhost:${port}`,
scopes
})
.then(onURL)
.catch(reject);
});
});
return pca.acquireTokenByCode({
code: requestUrl.searchParams.get('code'),
redirectUri: requestUrl.origin,
scopes
});
}
Promise.resolve()
.then(async () => {
// Probably cache all of these tokens, like minecraft-protocol does
// alternatively use pca.acquireTokenByDeviceCode()
// for acquisition of microsoft account auth
// https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/request.md
const msaAccessToken = await getAuthorizationTokenWithLocalhost(console.log);
console.log('msaAccessToken');
console.log(msaAccessToken.account.username);
console.log('expiresOn', prettyMilliseconds(new Date(msaAccessToken.expiresOn) - Date.now()));
console.log('');
const xblUserToken = await XboxLiveAuth.exchangeRpsTicketForUserToken('d=' + msaAccessToken.accessToken);
console.log('xblUserToken');
console.log('NotAfter', prettyMilliseconds(new Date(xblUserToken.NotAfter) - Date.now()));
console.log('');
const xsts = await XboxLiveAuth.exchangeUserTokenForXSTSIdentity(
xblUserToken.Token, {XSTSRelyingParty, raw: false}
);
console.log('xsts');
console.log('expiresOn', prettyMilliseconds(new Date(xsts.expiresOn) - Date.now()));
console.log('');
const mcaResponse = await fetch(URL_LOGIN_XBOX, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'User-Agent': USER_AGENT
},
body: JSON.stringify({identityToken: `XBL3.0 x=${xsts.userHash};${xsts.XSTSToken}`})
});
const mca = await mcaResponse.json();
console.log('mca');
console.log(mca.username);
console.log(prettyMilliseconds(mca.expires_in * 1000));
console.log('');
const profileResponse = await fetch(URL_MC_PROFILE, {
headers: {
'Content-Type': 'application/json',
'User-Agent': USER_AGENT,
Authorization: `Bearer ${mca.access_token}`
}
});
const profile = await profileResponse.json();
console.log('profile');
console.log(profile.name);
console.log('');
})
.catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment