Convert Xbox-Live GamerTag to XUID using Microsoft REST API - Java

5.5k Views Asked by At

I have a Java application which needs to be able to take a user-inputted gamertag for Minecraft-Bedrock Edition and convert it into the XUID of the of the given account so that I can store it off for whitelisting and reference purposes later.

I have been going through the Microsoft REST API docs looking for a method that will let me do this but the closest thing I have been able to find is this:

https://learn.microsoft.com/en-us/gaming/xbox-live/xbox-live-rest/uri/profilev2/uri-usersbatchprofilesettingspost

which still requires the XUID as input rather than providing it as the output.

Is there any way I can convert a given String input for a gamertag into the XUID of the associated account or null if no such account exists for a Java application?

1

There are 1 best solutions below

1
On

I have written an illustrative proof-of-concept implementation in pure, self-contained bash+curl+sed.

It is heavily inspired by plagiarized/condensed from the xbox.webapi.authentication.manager module from Team OpenXbox's Xbox-Webapi, which you should probably just use instead*. Theirs is such a good API, covering so much arcana that Microsoft… simply fails to document; that it would be worth strongly considering switching your project to Python just for this library, if it relies on Microsoft's Xbox Live API for its core functionality.

In a nutshell, to hit this API, it appears that you must:

  1. Register an Application in Azure

    • if your application can bind to localhost:8080 on the system of the user who is going to authorize the application, or you otherwise have their co-operation (specifically: they're able to paste the code parameter into the program from a URL in their browser), you may skip this step, use client_id=0000000048093EE3, and completely omit client_secret. (In this case, you do not even need an Azure account.)
  2. Get any** Xbox Live user to provide the Xboxlive.signin and Xboxlive.offline_access scopes to your application via OAuth2

  3. Use this authorization and a Bearer token to get a so-called "User Token" from https://user.auth.xboxlive.com/user/authenticate

  4. Use that token to authenticate yourself to https://xsts.auth.xboxlive.com/xsts/authorize to get an "XToken"

  5. Use that token to authenticate yourself to https://profile.xboxlive.com for the actual endpoints you're interested in, such as /users/gt({gamertag})/profile/settings (which contains, among other attributes, the XUID, as a decimal string, at property "id")

(**Obviously, if you're hitting privileged endpoints, such those that view private information or modify user account settings, you'll have additional requirements on whose authorization you need and what scopes you'll have to request; but, for the general case of gamertag-to-XUID lookup, a mere sign-in from any user is fine.)


*For this, it'd be something like:

from asyncio import run as arun
from sys import argv
from os import path, environ
import subprocess
from aiohttp import ClientSession
from xbox.webapi.api.client import XboxLiveClient
from xbox.webapi.authentication.manager import AuthenticationManager
from xbox.webapi.authentication.models import OAuth2TokenResponse

async def gamertags_to_xuids(gamertags, client_id=environ["client_id"], client_secret=environ["client_secret"], token_jar=path.join(environ["HOME"], ".local", "share", "xbox", "tokens.json")):
  assert len(gamertags) >= 1
  global session
  auth_mgr = AuthenticationManager(session, client_id, client_secret, "")
  await freshen_tokens(auth_mgr, token_jar)
  xbl_client = XboxLiveClient(auth_mgr)

  ids = []
  for gamertag in gamertags:
    profile = await xbl_client.profile.get_profile_by_gamertag(gamertag)
    ids.append(int(profile.profile_users[0].id))
  xuids = [f"{id:016X}" for id in ids]

  return xuids

async def freshen_tokens(auth_mgr, token_jar):
  with open(token_jar, "r+") as f:
    auth_mgr.oauth = OAuth2TokenResponse.parse_raw(f.read())
    await auth_mgr.refresh_tokens()
    f.seek(0)
    f.truncate()
    f.write(auth_mgr.oauth.json())

async def amain(args):
  global session
  subprocess.run(["xbox-authenticate"], check=True)#TODO: avoid this system call
  async with ClientSession() as session:
    return await gamertags_to_xuids(args)

def main(args=argv[1:]):
  return arun(amain(args))

if __name__ == '__main__':
  for xuid in main():
    print(xuid)