Skip to content

WIP XUser#33

Draft
olivi-r wants to merge 25 commits into
Weather-OS:masterfrom
olivi-r:master
Draft

WIP XUser#33
olivi-r wants to merge 25 commits into
Weather-OS:masterfrom
olivi-r:master

Conversation

@olivi-r
Copy link
Copy Markdown
Contributor

@olivi-r olivi-r commented Feb 13, 2026

This PR adds:

  • Stubs for the XUser interfaces
  • Minimal XLauncher implementation (moved to XLauncher Implementation #37)
  • Xbox Live token requesting
    • Currently missing login ui, requires manually adding an oauth refresh code to [HKLM\Software\Wine\WineGDK]"RefreshToken"
  • Most of the trivial XUser methods
  • XUserGetTokenAndSignature methods to generates tokens correctly, although signatures are still not generated.

Currently the oauth client_id / MSAAppId has to be manually set as MicrosoftGame.config parsing is not here yet.

Implemented
  • XUserDuplicateHandle
  • XUserCloseHandle
  • XUserCompare
  • XUserGetMaxUsers
  • XUserAdd *
  • XUserGetLocalId
  • XUserGetId
  • XUserGetIsGuest *
  • XUserGetState
  • XUserGetGamerPicture *
  • XUserGetAgeGroup
  • XUserCheckPrivilege
  • XUserGetTokenAndSignature[Utf16] *
  • XUserRegisterForChangeEvent
  • XUserUnregisterForChangeEvent
  • XUserIsSignOutPresent

* Likely to need further tweaking

Not currently planned for this PR

These methods are either deprecated, not for Windows, or just not essential for minimum viable implementation.

XUserFindUserByLocalId
XUserFindUserById
XUserResolvePrivilegeWithUi
XUserResolveIssueWithUi[Utf16]
XUserGetSignOutDeferral
XUserCloseSignOutDeferralHandle
XUserAddByIdWithUi
XUserGetMsaTokenSilently
XUserIsStoreUser
XUserPlatformRemoteConnectSetEventHandlers
XUserPlatformRemoteConnectCancelPrompt
XUserPlatformSpopPromptSetEventHandlers
XUserPlatformSpopPromptComplete
XUserSignOut

@olivi-r olivi-r force-pushed the master branch 2 times, most recently from 1fdc013 to 65c4dc0 Compare March 6, 2026 20:38
@Syntist
Copy link
Copy Markdown

Syntist commented Mar 22, 2026

Is this related to be able to login into Microsoft account? like in Minecraft Bedrock?

@olivi-r
Copy link
Copy Markdown
Contributor Author

olivi-r commented Mar 26, 2026

Is this related to be able to login into Microsoft account? like in Minecraft Bedrock?

Yes that is the purpose, although it is not yet complete

@ItsbaileyX3525
Copy link
Copy Markdown

Thank you for working on this! Can't wait to see a working product

@ChristopherHX
Copy link
Copy Markdown

ChristopherHX commented Apr 2, 2026

Somehow while pulling this into the default branch locally, for debugging purposes, I had a duplicated type definition error and applied this patch
diff --git a/include/xuser.idl b/include/xuser.idl
index 2f7292b..877c59c 100644
--- a/include/xuser.idl
+++ b/include/xuser.idl
@@ -37,7 +37,6 @@ typedef enum XUserState XUserState;
 typedef enum XUserPlatformOperationResult XUserPlatformOperationResult;
 typedef enum XUserPlatformSpopOperationResult XUserPlatformSpopOperationResult;
 
-typedef struct APP_LOCAL_DEVICE_ID APP_LOCAL_DEVICE_ID;
 typedef struct XUserDeviceAssociationChange XUserDeviceAssociationChange;
 typedef struct XUserGetTokenAndSignatureData XUserGetTokenAndSignatureData;
 typedef struct XUserGetTokenAndSignatureHttpHeader XUserGetTokenAndSignatureHttpHeader;
@@ -53,6 +52,20 @@ typedef void (__stdcall *XUserPlatformRemoteConnectShowPromptEventHandler)( PVOI
 typedef void (__stdcall *XUserPlatformRemoteConnectClosePromptEventHandler)( PVOID context, UINT32 userIdentifier, XUserPlatformOperation operation );
 typedef void (__stdcall *XUserPlatformSpopPromptEventHandler)( PVOID context, UINT32 userIdentifier, XUserPlatformOperation operation, LPCSTR modernGamertag, LPCSTR modernGamertagSuffix );
 
+cpp_quote("#if 0")
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+typedef unsigned __int3264 size_t;
+typedef unsigned int uint32_t;
+typedef int int32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+typedef boolean bool;
+typedef struct APP_LOCAL_DEVICE_ID
+{
+    BYTE value[32];
+} APP_LOCAL_DEVICE_ID;
+cpp_quote("#endif")
 
 enum XUserAddOptions
 {
@@ -170,11 +183,6 @@ enum XUserPlatformSpopOperationResult
     XUserPlatformSpopOperationResult_Canceled       = 3
 };
 
-struct APP_LOCAL_DEVICE_ID
-{
-    BYTE value[32];
-};
-
 struct XUserLocalId {
     UINT64 value;
 };

Didn't come to the point where my breakpoints hit reliable within wine gdk (somehow winegdk stopped in the wrong dll with a similar main.c)) / XUser was called for me. Fixed itself after recompiling via make clean, but now winedbg freezes if I make a small break of 20s and do not keep it running long enough.
Want to experiment with the XUser api, coming from the dark minecraft-linux side of things. Which has xbox auth for years.

@olivi-r
Copy link
Copy Markdown
Contributor Author

olivi-r commented Apr 9, 2026

Somehow while pulling this into the default branch locally, for debugging purposes, I had a duplicated type definition error and applied this patch

Didn't come to the point where my breakpoints hit reliable within wine gdk (somehow winegdk stopped in the wrong dll with a similar main.c)) / XUser was called for me. Fixed itself after recompiling via make clean, but now winedbg freezes if I make a small break of 20s and do not keep it running long enough. Want to experiment with the XUser api, coming from the dark minecraft-linux side of things. Which has xbox auth for years.

Thanks, I'm aware of this issue, I just haven't got round to pushing my changes yet.

To elaborate more on the auth hold up, the XUserGetTokenAndSignature methods return both the XToken for the authorization header and also a signature header of the provided message body, in my understanding the signature cannot be generated without the private key and encryption and key provisioning hasn't yet been worked out for msixvc packages, hence why they first have to be 'decrypted' through a windows installation.

Although I couldn't say for sure without further testing, as I am not super familiar with other projects, Minecraft/PlayFabApi may not verify the message integrity, which may allow a semi-stub of XUserGetTokenAndSignature methods to work albeit only for certain games. Either that or the clients act as mobile platforms in terms of auth which use a slightly different api, and would allow a mitm method, which isn't as useful here without a lot of game specific code.

The last part might be completely incorrect and if you know more please let me know 🙂

@ChristopherHX
Copy link
Copy Markdown

Minecraft/PlayFabApi may not verify the message integrity

I hope so (and understood this from your original post), but I almost had the conclusion that I have a much bigger problem that I do not have stub idl files of the unknown interfaces that might or not be other xbox live libraries.
Or could I somehow do the same as gameservices.dll.threading and try to load the ms binaries like I do on android?

My general Idea is to intercept the XCurl http client, if it finds the fake signature and remove that from the url. Since I would expect that a provied signature would be validated. Based on examples on msdocs, it reads like signature might be optional and could be NULL, however this depends on how the code interacts with the result.

I also read all cross platform games needs to somehow lift such a requirement, but anyhow ms might be able to apply this only on supported platforms.

XUserGetTokenAndSignature

I wonder did the game call this XUserGetTokenAndSignature function on your end? Could failed for me, since I yet have to figure out how you got the authenticated user credentials for injection.

The last part might be completely incorrect and if you know more please let me know 🙂

Yes I let you know once I have more time with experimenting with winegdk, till now no news.

@ChristopherHX
Copy link
Copy Markdown

ChristopherHX commented Apr 16, 2026

One blocker for proper validation the xtoken code is this requested class and interface:

973a344e_24bf_4d0f_8457_56c534892b29: XGame or whatever
2549f142_6419_4a06_97b5_931aab7c2f34: subinterface or whatever
XGameGetXboxTitleId: 0x18 : 3
XLaunchNewGame: 4
XLaunchRestartOnCrash: 5

The titleid is most likely used to call XblInitialize. (xbox-live GDK calls this method itself during init based on source code via a Xal Wrapper)

https://github.com/microsoft/Xbox-GDK-Samples/blob/0a55b37c94dcab36e84b44227e331baa535ace57/Kits/LiveTK/LiveResources.cpp#L68-L79

Maybe it would help me to compile some gdk samples with debug info and link with the debug variant of xbox live static library, which is statically linked into minecraft.

An invalid titleid would possible result in errors.

@olivi-r
Copy link
Copy Markdown
Contributor Author

olivi-r commented Apr 16, 2026

TitleId is another field in MicrosoftGame.config, (for Minecraft this is 35760C07) which still needs parsing to retrieve the MSAAppId which is passed as the client_id field when requesting an oauth token. That's two things that can be done at once, and should probably be handled in GDKC_InitApi.

I've been very busy recently but I will try to make some time to get that part working, although as mentioned prior, XUserGetTokenAndSignature is more of the main focus as xsapi is built on top of xgameruntime rather than being wholly separate. Which still cannot be completed fully until more is understood about the drm.

@ChristopherHX
Copy link
Copy Markdown

ChristopherHX commented Apr 16, 2026

TitleId is another field in MicrosoftGame.config, (for Minecraft this is 35760C07)

Yes it is, I am still learning slowly how to implement missing class stubs due to almost no documentation how the com impl had been created here.

TLDR hiding the long message

I might really hardcode this in my local hacks, it is fully understandable for a good implementation this needs to be read from the game.

XUserGetTokenAndSignature

If I return garbage here, the game seem to repeatedly call this with playfab urls, but trying to understand where the http calls actually flow. XS api does not look to use XCurl, but playfab uses XCurl. Given I never tried protongdk, I do not know if XCurl has connectivity issues itself.

minecraft android xsapi also uses it's own httpclient, just it makes verbose java native interface calls and we have the httpclient c++ source code, actually I might be able to compile the http client for GDK from scratch that is based on WinHttp for debugging. wine is really shocking me, just recompiled once and the debugger ignores breakpoints again..m

XUserGetTokenAndSignature is more of the main focus as xsapi is built on top of xgameruntime rather than being wholly separate.

My focus might be a bit different :) and specially target xsapi that might use XUser to some extend.

EDIT Added sourcecode to xs-api on GitHub, the last time I searched for xbox api code the repo was empty as far as I remember, interesting

EDIT2
https://github.com/microsoft/xbox-live-api/blob/dd61050a95039108489b9deef7ba5c0945573850/Source/Shared/http_call_wrapper_internal.cpp#L710-L718

The public xbox sdk used in GDK does not require signature.

@ChristopherHX
Copy link
Copy Markdown

ChristopherHX commented Apr 17, 2026

Further research the XalUserGetTokenAndSignatureSilentlyAsync I have running in mcpelauncher, does generate the signature part of XUserGetTokenAndSignatureAsync that GDK wants. It using sha + ecdsa signing on android / mcpelauncher linux + macOS, for this. In a MVP, Minecraft ChromeOS Trial that is available free of charge could be used by my reference implementation that generates even the signature for winegdk. The android xal sdk has debug symbols, that possible can provide insights how to generate the signature directly in wine.

I believe that I need to debug also on windows, to get to know why the XUser api usage get stuck

Both GDK and android have similar behavior here, up to a point where my GDK setup has problems.

  • SignInSilently (GDK|android)
  • GetGamerTag + displaying it (GDK|android) /* altering the first returned string ends up on the home screen */
  • GetTokenAndSignature for playfab (Marketplace, inbox etc.) (GDK|android) => successful marketplace login both /* only in winedbg for gdk, since login has a phantom abort in winegdk and just hangs without debugger without attempting to abort the blocking load operation to allow marketplace */
  • XblContextCreateHandle (android) GDK unknown, no debug symbols like on android
    • GetGamerTagComponent (GDK|android) not called by GDK
  • GetTokenAndSignature the signature part is ignored until here, but since GDK does not run to this point yet that field is no longer the most important one.

XCurl is libcurl built from source with debug symbols

  • XCurl from MS hangs up in winegdk, possible similar issue why xbl init hangs up

@olivi-r
Copy link
Copy Markdown
Contributor Author

olivi-r commented Apr 18, 2026

Fixed the APP_LOCAL_DEVICE_ID include as well as reworked token methods into a separate interface.

Additionally left the msaAppId hard-coded with Minecraft's until I get MicrosoftGame.config parsing done.

Additional details on how to get refresh token working for now
curl 'https://login.live.com/oauth20_connect.srf' -d 'client_id=0000000040159362&scope=service::user.auth.xboxlive.com::MBI_SSL&response_type=device_code' -H 'Content-Type: application/x-www-form-urlencoded'

Visit https://microsoft.com/link and enter the user_code field from the response and sign in.

Then using the device_code field:

curl 'https://login.live.com/oauth20_token.srf' -d 'device_code=<device_code>&client_id=0000000040159362&grant_type=device_code' -H 'Content-Type: application/x-www-form-urlencoded'

Finally update the registry with the refresh_token from the response:

wine reg add 'HKLM\Software\Wine\WineGDK' /v RefreshToken /d <refresh_token>

@ChristopherHX ChristopherHX mentioned this pull request Apr 19, 2026
@olivi-r olivi-r force-pushed the master branch 5 times, most recently from 64dbb17 to 16ad285 Compare April 20, 2026 12:15
@olivi-r olivi-r deleted the branch Weather-OS:master April 26, 2026 16:40
@olivi-r olivi-r closed this Apr 26, 2026
@olivi-r olivi-r deleted the master branch April 26, 2026 16:40
@olivi-r olivi-r restored the master branch April 26, 2026 16:41
@olivi-r olivi-r reopened this Apr 26, 2026
@Weather-OS
Copy link
Copy Markdown
Owner

Nice work! I'll watch this repo and see if I could contribute anything myself as well.

@olivi-r
Copy link
Copy Markdown
Contributor Author

olivi-r commented Apr 29, 2026

XUserGetTokenAndSignature methods partially implemented, signature is ignored for now.
Occasionally crashes in Minecraft as well, possibly due to unchecked access of signature field, will need to experiment more.

It's possible that the token is expected to be formatted for direct use in the Authorization header i.e formatted as XBL3.0 x=<uhs>;<token> the docs are quite unclear here and its annoying to right tests against authenticated methods on windows as they tend to fail unless the app is packaged.

@birdayz
Copy link
Copy Markdown

birdayz commented May 10, 2026

@olivi-r a few weeks ago i worked with Claude Opus 4.6 on this. got pretty far, but some microsoft games live stuff was missing.. so i could play e.g. MobMaze and other provided servers.

but struggled to get realms, friendlist and world joining working
marketplace worked! also "Servers" tab.

i didn't have the time anymore to keep working on it. maybe this is useful.

providing a full brain dump here, in case it helps you with your work.

btw, totally appreciate your work. i'm dead serious, this is very valuable to all of gamers and linux users!


  Summary of my WineGDK + Minecraft Bedrock online play work

  Branch: xuser-olivi in my WineGDK fork (72 commits, +1620 lines across 17 files)
  Game version tested: Minecraft Bedrock v1.26.12 on Arch Linux with GDK-Proton10-32
  Result: Full Xbox Live sign-in and online multiplayer (Servers tab) working. Friends/Realms still broken.

  ---
  What works (fully functional)

  1. Complete Xbox Live auth chain in xgameruntime.dll:
  - MSA refresh token → OAuth access token (via login.live.com)
  - OAuth → XBL User Token (user.auth.xboxlive.com)
  - XBL → XSTS Token (xsts.auth.xboxlive.com)
  - Per-relying-party XSTS tokens (e.g. https://b980a380.minecraft.playfabapi.com/)
  - Device auth with EC P-256 key pair (device.auth.xboxlive.com)
  - ECDSA request signing for XBL3.0 authenticated requests
  - All 36+ Minecraft service endpoints returning HTTP 200

  2. XUser implementation:
  - XUserAddAsync / XUserGetId / XUserGetGamertag / XUserGetState
  - XUserGetTokenAndSignatureAsync with proper signing
  - XUserChangeEvent firing (SignedInAgain, Gamertag, Privileges)
  - Async operations using proper XAsyncBegin → provider → DoWork → XAsyncComplete → GetResult pattern

  3. XStore license verification:
  - XStoreQueryGameLicenseAsync returns isActive=true with proper SKU (9NBLGGH2JHXJ)
  - Uses real XAsync pattern through native threading DLL

  4. GDK infrastructure:
  - XGameRuntimeInitialize / InitializeApiImplEx2 with COM init
  - QueryApiImpl routing for XSystem, XThreading, XNetworking, XUser, XStore, service broker
  - DllGetClassObject class factory for XSAPI telemetry CLSID {834366da}
  - Service broker {af406016} with 141-entry vtable, IsServiceAvailable returns TRUE
  - Process task queue creation/assignment on native threading DLL
  - XSystemGetXboxLiveSandboxId / XSystemGetConsoleId / XSystemGetAppSpecificDeviceId

  5. isSignedIn memory patch (version-independent pattern scan):
  - Scans for the function prologue + mov rcx, [rcx+0x50] (userManager) + mov edx, 1 (XboxLive enum)
  - Patches to mov eax, 1; ret — bypasses user->isConnected(XboxLive) check
  - Applied during InitializeApiImplEx2 (no timing dependency on WINEDEBUG)

  6. Credential gate bypass (Patch 3):
  - NOPs a JL instruction that skips XblInitialize when the game's credential provider returns E_FAIL without Gaming Services
  - Pattern: cmp [rbp-0x18], 0; JL followed by xorps xmm0,xmm0; xor eax,eax

  7. Online play confirmed on:
  - Hive, MobMaze servers via Servers tab
  - Avatar, gamertag, marketplace all functional

  ---
  What doesn't work / remaining blockers
  
  1. Friends/Realms tabs — need XSAPI social manager:
  - The game's isConnected(XboxLive) is set by _onPrimaryUserConnectComplete(Connected)
  - This callback fires when XSAPI social manager completes init
  - Requires: XblInitialize → XblSocialManagerAddLocalUser → RTA WebSocket to wss://rta.xboxlive.com/connect → XblSocialManagerDoWork pump

  2. XblInitialize succeeds (S_OK) but causes downstream crash:
  - Root cause was XSystemGetXboxLiveSandboxId returning E_POINTER when sandboxIdUsed is NULL (fixed)
  - XblInitArgs layout confirmed: { XTaskQueueHandle queue; const char *scid; } with SCID 4fc10100-5f7a-4470-899b-280835760c07
  - After init succeeds, XSAPI's internal thread hits a page fault: access violation reading 0xFFFFFFFFFFFFFFF0 (NULL-16) at game RVA 0x722F372 — vtable dispatch on NULL object
  - Likely XSAPI tries to use infrastructure we don't fully provide
  - Currently disabled to keep the game stable
  
  3. NtQueryWnfStateData — unimplemented in Wine 10.0:
  - GameInputRedist.dll indirectly triggers ntdll.dll.NtQueryWnfStateData
  - Cannot be IAT-hooked (goes through ntdll's internal syscall dispatch)
  - Cannot patch PE ntdll (function is Unix-side only in Wine)
  - Workaround: disable GameInputRedist with GameInputRedist=b override
  - Proper fix: rebuild Wine's ntdll.so with WNF stub, or upgrade to newer Wine/Proton that has it
  
  4. The memory patch is still needed:
  - Without XSAPI social manager completing, isConnected(XboxLive) never becomes true naturally
  - The game detects Win32 PC via ConsoleMode registry and takes a fallback sign-in path that does PlayFab + franchise auth but NEVER initializes XSAPI
  
  ---
  Key technical findings for other implementors

  - ConsoleMode registry: HKLM\Software\Microsoft\Windows NT\CurrentVersion\OEM\ConsoleMode controls the game's code path. Value 1 = Win32 PC (skips XSAPI). Value 8 works for our purposes.
  - XSAPI is statically linked into Minecraft.Windows.exe — all function addresses are version-specific. XblInitialize at RVA 0x876C880 in v1.26.12.
  - XblInitialize flow: Gets XThreadingImpl → creates task queues → InitializeApiImplEx2 → XNetworking → queries PlayFab Multiplayer {973a344e} (E_NOINTERFACE OK) → XSystemGetXboxLiveSandboxId
   → returns S_OK.
  - The game loads xgameruntime.dll via LoadLibraryExA("xgameruntime.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32) — our Wine DLL intercepts this.
  - Auth token storage: MSA refresh token stored in HKLM\Software\Wine\WineGDK\RefreshToken (obtained via ProxyPass/gophertunnel initial auth flow).
  - XAsync deadlock: Fixed reentrant spinlock in XAsyncBegin/XAsyncSchedule — the native threading DLL's XAsync can deadlock if the provider's Begin op calls XAsyncSchedule synchronously.
  - windows.web.dll is needed as a Wine DLL for JSON parsing (IJsonObject) used in OAuth/XBL/XSTS response parsing.
  
  ---
  Files/structure

  dlls/xgameruntime/
  ├── main.c                    (573 lines — init, patches, QueryApiImpl routing, COM factory)
  ├── GDKComponent/System/
  │   ├── User/XUser.c          (1041 lines — XUserAdd, GetId, GetGamertag, change events)
  │   ├── User/Token.c          (604 lines — OAuth, XBL, XSTS token requests via WinHTTP)
  │   ├── User/DeviceAuth.c     (360 lines — EC P-256 keygen, device token, ECDSA signing)
  │   ├── XStore.c              (196 lines — game license async with proper XAsync)
  │   ├── XServiceBroker.c      (120 lines — 141-entry vtable composite)
  │   ├── XSystem.c             (sandbox ID, console ID, device ID)
  │   └── Threading/XAsync.c    (123 lines — deadlock fix)
  └── xgameruntime.spec         (exports)

Full code of mine can be found in my fork.
https://github.com/birdayz/WineGDK/tree/xuser-olivi

@olivi-r
Copy link
Copy Markdown
Contributor Author

olivi-r commented May 10, 2026

Thanks, I've been a bit burned out from this the last few days. I will take a look through to see if anything is useful, although as with @ChristopherHX's fork, we can't guarantee that AI generated code is cleanroom compliant.

@ChristopherHX
Copy link
Copy Markdown

ChristopherHX commented May 10, 2026

My code has been rejected as non compliant that looks to be much newer while the results are 99% similar, I would no longer recommend looking at my code unless you want to risk your ability to contribute. Likewise in other projects where yours is e.g. MIT licensed and the fork is GPL, once you look at the code you risk way too much to reproduce code that does not follow the license / guidelines.

Forbidden things for winegdk contributors, as I understood

  • Do not use winedbg even if the code you are debugging is MIT licensed, but you used any headers under a different / unspecified license or a .lib where this is the case. My PR about this is closed (this is at best grey area) even if this was just to not return E_POINTER from XSystem
  • Never ever look at the disassembly of any .dll from windows, the game etc.
    • This would exclude any binary or instruction patching claude did
    • Maybe better also not look at any header file from microsoft EULA sdks, any content there is non compliant as wine source code
  • Only ever debug things the classic time consuming way, make trace points

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.

6 participants