Authenticating a Microsoft account

This article aims to document how to log in to a Microsoft account to authenticate with Minecraft.

WARNING: This is not a finished article!

There are two ways to authenticate a Microsoft account - via the email and password or via OAuth 2. Both ways will be outlined in this article.

Email & Password

Note: You will need to enable redirects with whatever request library you're using. You will also need to be able to see the final request URL after redirects. You also must use the same session for the following requests (for example, requests.Session() in the Python requests library).

Preparing to log in

Before we sign in, we first need to extract two values that we will need in order to sign in.

Send a GET request to https://login.live.com/oauth20_authorize.srf?client_id=000000004C12AE6F&redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=service::user.auth.xboxlive.com::MBI_SSL&display=touch&response_type=token&locale=en, then in the page source find the sFTTag value:

sFTTag:'<input type="hidden" name="PPFT" id="i0327" value="Value we want is here!"/>'

In testing, using the regular expression value="(.+?)" and extracting the first group is an easy way to extract this value. Save it, as it is needed for the second step.

We also need to get the urlPost value from the page source:

urlPost:'The value we want is in here!'

The regular expression urlPost:'(.+?)' works fine for this, just extract the first group. Save this value.

You may need to modify these regular expressions if, for example, the response text escapes single quotes.

Take note that you CANNOT move on to the next step unless you have both of these values.

Signing in to Microsoft

Now that we have the required values, let's sign into Microsoft. In order to do this, we must send a POST request to the URL in the urlPost value we saved in the first step.

The POST request must have the body of:

login=EMAIL_HERE&loginfmt=EMAIL_HERE&passwd=PASSWORD_HERE&PPFT=SFTTAG_VALUE_HERE

Make sure you URL encode the email, password, and sFTTag value. The Content-Type header should be set to application/x-www-form-urlencoded. Make sure you also enable following redirects in whatever request library you use.

After the request is done following all redirects, check if "accessToken" is present in the new URL, and if the new URL is the same as the urlPost URL that we first sent the request to. If both of these things are the case, the login failed.

If the page source contains "Sign in to", your credentials were wrong. If the page source contains "Help us protect your account", 2-factor authentication is enabled on this account and must be removed or you need to enter your security information to confirm the login.

Now we need to get the tokens that were returned inside this URL. Split the new URL by # so that you can get just the URL parameters and their values. You can then split the string again by & to get each param=value pair, and again to each pair split by = to get the parameter name and value. Store these values however you wish.

Some Python example code:

raw_login_data = login_request.url.split("#")[1] # split the url to get the parameters
login_data = dict(item.split("=") for item in raw_login_data.split("&")) # create a dictionary of the parameters
login_data["access_token"] = requests.utils.unquote(login_data["access_token"]) # URL decode the access token
login_data["refresh_token"] = requests.utils.unquote(login_data["refresh_token"]) # URL decode the refresh token
print(login_data) # print the data

This code returns the data in a dict, like so:

{
   'access_token': 'access token here',
   'token_type': 'bearer',
   'expires_in': '86400',
   'scope': 'service::user.auth.xboxlive.com::MBI_SSL',
   'refresh_token': 'refresh token here',
   'user_id': 'user id here'
}

Save the access_token value (and possibly the refresh_token value if you want!) and we can move on to the next step! Skip the "OAuth 2" section and move straight onto "Signing into Minecraft"!

OAuth 2

Note: Before anything else, you must first get an OAuth 2 Client ID and Client Secret for your MSA. You can do this by clicking here to register an Azure application.

Logging into the MSA

You must do this step in a browser.

Navigate to the following URL: https://login.live.com/oauth20_authorize.srf?client_id=AZURE_CLIENT_ID_HERE&response_type=code&redirect_uri=REDIRECT_URI_HERE&scope=XboxLive.signin%20offline_access&state=NOT_NEEDED.

From here, you'll be prompted to enter your MSA login information, and on a successful signin you'll be redirected to the following URL: https://REDIRECT_URI_HERE?code=CODE_HERE&state=NOT_NEEDED. The code parameter must be extracted as you'll need this later on.

Get an access token

After you have your code, you need to get your access token. This needs your client secret from earlier. Keep this client secret safe!

Then, send a POST request to https://login.live.com/oauth20_token.srf with the following POST body and the header Content-Type: application/x-www-form-urlencoded:

client_id=CLIENT_ID_HERE&client_secret=CLIENT_SECRET_HERE&code=CODE_FROM_PREVIOUS_STEP&grant_type=authorization_code&redirect_uri=REDIRECT_URI_HERE

If the request is successful, it will return a sample response such as this:

{
    "token_type": "bearer",
    "expires_in": 86400,
    "scope": "XboxLive.signin",
    "access_token": "ACCESS_TOKEN_HERE",
    "refresh_token": "M.R3_BAY.REFRESH_TOKEN_HERE",
    "user_id": "USER_ID_HERE",
    "foci": "1"
}

If you want to refresh an existing access_token, you can use the refresh_token and send a slightly different request - use the POST body:

client_id=CLIENT_ID_HERE&client_secret=CLIENT_SECRET_HERE&refresh_token=REFRESH_TOKEN_HERE&grant_type=refresh_token&redirect_uri=REDIRECT_URI_HERE

You will get the same response as shown above if the request is successful. Save the access_token and move onto "Signing into Minecraft"!

Signing into Minecraft

Now that we have signed into Microsoft, we can use the Microsoft access token in order to sign in to Minecraft. These steps are the same regardless of if you use OAuth 2 or plain email and password login.

Signing into Xbox Live

You now must sign into Xbox Live. In order to do this, you must send a POST request to https://user.auth.xboxlive.com/user/authenticate with the following body, and the headers Content-Type: application/json and Accept: application/json:

Note: You may need to add d= before the access token. Some users report they cannot sign into Xbox Live unless they add d= before the token (like so: d=ACCESS_TOKEN_HERE). Others report the exact opposite, being able to sign in without d=. I (the author of this article) report being able to only sign in without d=, so that is what I will show here in this example body. There is a possibility (although not fully proven as of the time of writing this) that the need for adding d= only exists when signing into Xbox Live with oAuth 2. Keep this in mind when using this endpoint, and please make a GitHub issue if you can disprove this claim.

{
    "Properties": {
        "AuthMethod": "RPS",
        "SiteName": "user.auth.xboxlive.com",
        "RpsTicket": "ACCESS_TOKEN_HERE" // you may need to add "d=" before the access token as mentioned earlier
    },
    "RelyingParty": "http://auth.xboxlive.com",
    "TokenType": "JWT"
}

If all is successful, you will see a response similar to the below sample response:

{
    "IssueInstant": "2021-02-07T16:43:21.3324153Z",
    "NotAfter": "2021-02-21T16:43:21.3324153Z",
    "Token": "TOKEN_HERE",
    "DisplayClaims": {
      "xui": [
         {
            "uhs": "USER_HASH_HERE"
         }
      ]
    }
}

Save the Token and the uhs values and move onto the next step!

Getting an XSTS token

This is the final step before we can log in with Minecraft! Send a POST request to https://xsts.auth.xboxlive.com/xsts/authorize with the following JSON body and the headers Content-Type: application/json and Accept: application/json:

{
    "Properties": {
        "SandboxId": "RETAIL",
        "UserTokens": [
            "TOKEN_HERE_FROM_PREVIOUS_STEP"
        ]
    },
    "RelyingParty": "rp://api.minecraftservices.com/",
    "TokenType": "JWT"
}

You can either get a successful response or a 401 response.

Successful response:

{
    "IssueInstant": "2021-02-07T21:41:03.6735105Z",
    "NotAfter": "2021-02-08T13:41:03.6735105Z",
    "Token": "SAVE_THIS_TOKEN",
    "DisplayClaims": {
      "xui": [
         {
            "uhs": "SAME_USER_HASH_AS_BEFORE"
         }
      ]
    }
}

401: Unauthorized

{
    "Identity": "0",
    "XErr": 2148916238, // can either be 2148916238 (account belongs to someone under 18 and needs to be added to a family) or 2148916233 (account has no Xbox account, you must sign up for one first)
    "Message": "",
    "Redirect": "https://start.ui.xboxlive.com/AddChildToFamily"
}

Getting the bearer token for Minecraft

Now, we can finally get the Minecraft bearer token. Send a POST request to https://api.minecraftservices.com/authentication/login_with_xbox. The POST body should be similar to:

{
   "identityToken" : "XBL3.0 x=USER_HASH_HERE;XSTS_TOKEN_FROM_PREVIOUS_STEP",
   "ensureLegacyEnabled" : true
}

You must send this request with the Content-Type: application/json header.

You will get a response similar to this:

{
  "username" : "830491e6-50e9-e9ed-6e8a-7041f4fef585", // Xbox account username (?)
  "roles" : [ ], // i suppose this will have something in it if the account has a copy of Minecraft
  "access_token" : "eyJhbGciOiJIUzI1NiJ9.eyJ4dWlkIjogIjI1NTY3MzEwMzg0NzMzNTUiLCJzdWIiOiAiOGQ2YzVhMTItMzk2ZS00OWE1LTk1Y2QtZTczYmExODllNTIzIiwibmJmIjogMTYwNjg0NTE0Niwicm9sZXMiOiBbXSwiaXNzIjogImF1dGhlbnRpY2F0aW9uIiwiZXhwIjogMTYwNjkzMTU0NiwiaWF0IjogMTYwNjg0NTE0NiwieXVpZCI6ICIyMWQyZDJmOWUyYzU0MmQ0OGZlMmJiMjY4MzhmYjhkMiJ9.-7H1jT3i54gmbqQcUBdHArOn-Jr8eZVAyPDiOr5q_XY", // access token
  "token_type" : "Bearer", // don't think there are other types
  "expires_in" : 86400 // number of seconds until token expires. MSA tokens last 24 hours. yes, really, 24 hours!
}

The access_token is what you will now use to authenticate yourself to other API endpoints.

See the "A peek into Bearer tokens" article for more information about what's inside the access_token.