package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/url" "os" "path/filepath" "time" ) const client_id string = "9305aeb8-5ecb-4e7a-b28f-c33aefcfbd8d" type Authentication struct { Access authenticationResp XboxAuth xboxAuthResponse XboxAPI xboxAuthResponse McAPI xboxAuthResponse } type devCodeResp struct { User_code string Device_code string Verification_uri string Expires_in string Interval int Message string } type authenticationResp struct { Access_token string Token_type string Refresh_token string Expires_in string Error string Error_description string } type xboxAuthProperties struct { AuthMethod string SiteName string RpsTicket string } type xboxAuthRequest struct { Properties xboxAuthProperties RelyingParty string TokenType string } type xboxDisplayClaim struct { Uhs string Gtg string Xid string Agg string Usr string Utr string Prv string } type xboxDisplayClaims struct { Xui []xboxDisplayClaim } type xboxAuthResponse struct { IssueInstant time.Time NotAfter time.Time Token string DisplayClaims xboxDisplayClaims } type XSTSProperties struct { SandboxId string UserTokens []string } type XSTSRequest struct { Properties XSTSProperties RelyingParty string TokenType string } type McAuthRequest struct { Xtoken string `json:"xtoken"` Platform string `json:"platform"` } type McAuthRequest2 struct { IdentityToken string `json:"identityToken"` EnsureLegacyEnabled bool `json:"ensureLegacyEnabled"` } func main() { auth := Authentication{} dir, _ := os.UserConfigDir() if _, err := os.Stat(filepath.Join(dir, "minecraft_test", "authentication.json")); err != nil { resp, err := http.PostForm("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", url.Values{ "client_id": {client_id}, "scope": {"XboxLive.SignIn XboxLive.offline_access"}, }) if err != nil { fmt.Printf("Device Auth Step: %s\n", err) return } defer resp.Body.Close() if resp.StatusCode != 200 { fmt.Printf("Device Auth Step: %v\n", resp.Status) return } data, _ := io.ReadAll(resp.Body) codeResp := devCodeResp{} json.Unmarshal(data, &codeResp) fmt.Println(codeResp.Message) ticker := time.NewTicker(time.Second * time.Duration(codeResp.Interval)) defer ticker.Stop() for range ticker.C { resp, err := http.PostForm("https://login.microsoftonline.com/consumers/oauth2/v2.0/token", url.Values{ "client_id": {client_id}, "grant_type": {"urn:ietf:params:oauth:grant-type:device_code"}, "device_code": {codeResp.Device_code}, }) if err != nil { fmt.Printf("Authentication Request Error: %s\n", err) } defer resp.Body.Close() //if resp.StatusCode != 200 { // fmt.Printf("Authentication Request Error: %s\n", resp.Status) //} data, _ := io.ReadAll(resp.Body) authResp := authenticationResp{} json.Unmarshal(data, &authResp) if authResp.Error == "" { fmt.Printf("Authenticated!\n") auth.Access = authResp break } } } else { f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "authentication.json"), os.O_CREATE|os.O_RDWR, 0755) data, _ := io.ReadAll(f) json.Unmarshal(data, &auth.Access) resp, err := http.PostForm("https://login.microsoftonline.com/consumers/oauth2/v2.0/token", url.Values{ "client_id": {client_id}, "grant_type": {"refresh_token"}, "refresh_token": {auth.Access.Refresh_token}, "scope": {"XboxLive.SignIn XboxLive.offline_access"}, }) if err != nil { fmt.Printf("Authentication Request Error: %s\n", err) } defer resp.Body.Close() //if resp.StatusCode != 200 { // fmt.Printf("Authentication Request Error: %s\n", resp.Status) //} data, _ = io.ReadAll(resp.Body) authResp := authenticationResp{} json.Unmarshal(data, &authResp) if authResp.Error == "" { fmt.Printf("Authenticated!\n") auth.Access = authResp } } os.MkdirAll(filepath.Join(dir, "minecraft_test"), 0755) f, _ := os.OpenFile(filepath.Join(dir, "minecraft_test", "authentication.json"), os.O_CREATE|os.O_RDWR, 0755) defer f.Close() data, _ := json.Marshal(auth.Access) f.Write(data) req, _ := json.Marshal(xboxAuthRequest{Properties: xboxAuthProperties{AuthMethod: "RPS", SiteName: "user.auth.xboxlive.com", RpsTicket: "d=" + auth.Access.Access_token}, RelyingParty: "http://auth.xboxlive.com", TokenType: "JWT"}) client := http.Client{} httpReq, _ := http.NewRequest("POST", "https://user.auth.xboxlive.com/user/authenticate", bytes.NewBuffer(req)) httpReq.Header.Add("x-xbl-contract-version", "1") httpReq.Header.Add("Content-Type", "application/json") httpReq.Header.Add("Accept", "application/json") httpResp, err := client.Do(httpReq) if err != nil { fmt.Printf("XboxLive Error: %s\n", err) } defer httpResp.Body.Close() if httpResp.StatusCode != 200 { fmt.Printf("XboxLive Error: %s\n", httpResp.Status) } d, _ := io.ReadAll(httpResp.Body) json.Unmarshal(d, &auth.XboxAuth) xstsData, _ := json.Marshal(XSTSRequest{Properties: XSTSProperties{SandboxId: "RETAIL", UserTokens: []string{auth.XboxAuth.Token}}, RelyingParty: "http://xboxlive.com", TokenType: "JWT"}) httpXstsReq, _ := http.NewRequest("POST", "https://xsts.auth.xboxlive.com/xsts/authorize", bytes.NewBuffer(xstsData)) httpXstsReq.Header.Add("Content-Type", "application/json") httpResp, err = client.Do(httpXstsReq) if err != nil { fmt.Printf("XboxLive STS error: %s\n", err) } defer httpResp.Body.Close() if httpResp.StatusCode != 200 { fmt.Printf("XboxLive STS error: %s\n", httpResp.Status) } d, _ = io.ReadAll(httpResp.Body) json.Unmarshal(d, &auth.XboxAPI) xstsData, _ = json.Marshal(XSTSRequest{Properties: XSTSProperties{SandboxId: "RETAIL", UserTokens: []string{auth.XboxAuth.Token}}, RelyingParty: "rp://api.minecraftservices.com/", TokenType: "JWT"}) httpXstsReq, _ = http.NewRequest("POST", "https://xsts.auth.xboxlive.com/xsts/authorize", bytes.NewBuffer(xstsData)) httpXstsReq.Header.Add("Content-Type", "application/json") httpResp, err = client.Do(httpXstsReq) if err != nil { fmt.Printf("Minecraft STS error: %s\n", err) } defer httpResp.Body.Close() if httpResp.StatusCode != 200 { fmt.Printf("Minecraft STS error: %s\n", httpResp.Status) } d, _ = io.ReadAll(httpResp.Body) json.Unmarshal(d, &auth.McAPI) if auth.McAPI.DisplayClaims.Xui[0].Uhs != auth.XboxAPI.DisplayClaims.Xui[0].Uhs { fmt.Printf("Warning: Inconsistant user hash!") } mcAuthData, _ := json.Marshal(McAuthRequest2{IdentityToken: "XBL3.0 x=" + auth.McAPI.DisplayClaims.Xui[0].Uhs + ";" + auth.McAPI.Token, EnsureLegacyEnabled: true}) fmt.Printf("MC Auth Data: %s\n", mcAuthData) httpReqMC, _ := http.NewRequest("POST", "https://api.minecraftservices.com/authentication/login_with_xbox", bytes.NewBuffer(mcAuthData)) httpReqMC.Header.Add("Content-Type", "application/json") httpReqMC.Header.Add("Accept", "application/json") resp, err := client.Do(httpReqMC) if err != nil { fmt.Printf("MC Auth Error: %s\n", err) } defer resp.Body.Close() if resp.StatusCode != 200 { fmt.Printf("MC Auth Error: %s\n", resp.Status) } d, _ = io.ReadAll(resp.Body) fmt.Printf("MC Auth Response: %s\n", d) /* fmt.Println("Requesting Oauth") token, err := auth.RequestLiveToken() if err != nil { fmt.Println(err) return } else { ts := auth.RefreshTokenSource(token) fmt.Println("Generating Key") key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { fmt.Println(err) return } ctx := context.Background() fmt.Println("Requesting XBL Token") token, err = ts.Token() if err != nil { fmt.Println(err) return } xbl, err := auth.RequestXBLToken(ctx, token, "rp://api.minecraftservices.com/") if err != nil { fmt.Println(err) return } fmt.Println("Requesting Minecraft Chain") ctx = context.Background() _, err = auth.RequestMinecraftChain(ctx, xbl, key) if err != nil { fmt.Println(err) return } }*/ }