@@ -100,11 +100,74 @@ public static void login(String email, String password)
100100 throws LoginException
101101 {
102102 MinecraftProfile mcProfile = getAccount (email , password );
103+ setSession (mcProfile );
104+ }
105+
106+ public static void loginWithToken (String token ) throws LoginException
107+ {
108+ if (token == null || token .isBlank ())
109+ throw new LoginException ("Token cannot be empty." );
103110
104- User session = new User (mcProfile .getName (), mcProfile .getUUID (),
105- mcProfile .getAccessToken (), Optional .empty (), Optional .empty ());
111+ String trimmedToken = token .trim ();
112+ System .out .println ("Logging in with token..." );
113+ long startTime = System .nanoTime ();
106114
107- WurstClient .IMC .setWurstSession (session );
115+ try
116+ {
117+ try
118+ {
119+ MinecraftProfile mcProfile = getMinecraftProfile (trimmedToken );
120+ setSession (mcProfile );
121+ System .out .println ("Token login successful after "
122+ + (System .nanoTime () - startTime ) / 1e6D + " ms" );
123+ return ;
124+
125+ }catch (LoginException ignored )
126+ {
127+ // Token may be a Microsoft token instead of a Minecraft token.
128+ }
129+
130+ MinecraftProfile mcProfile =
131+ getAccountFromMicrosoftAccessToken (trimmedToken );
132+ setSession (mcProfile );
133+ System .out .println ("Token login successful after "
134+ + (System .nanoTime () - startTime ) / 1e6D + " ms" );
135+
136+ }catch (LoginException e )
137+ {
138+ System .out .println ("Token login failed after "
139+ + (System .nanoTime () - startTime ) / 1e6D + " ms" );
140+ throw e ;
141+ }
142+ }
143+
144+ public static void loginWithRefreshToken (String refreshToken )
145+ throws LoginException
146+ {
147+ if (refreshToken == null || refreshToken .isBlank ())
148+ throw new LoginException ("Refresh token cannot be empty." );
149+
150+ System .out .println ("Logging in with refresh token..." );
151+ long startTime = System .nanoTime ();
152+
153+ try
154+ {
155+ String msftAccessToken =
156+ getMicrosoftAccessTokenFromRefreshToken (refreshToken .trim ());
157+
158+ MinecraftProfile mcProfile =
159+ getAccountFromMicrosoftAccessToken (msftAccessToken );
160+ setSession (mcProfile );
161+
162+ System .out .println ("Refresh-token login successful after "
163+ + (System .nanoTime () - startTime ) / 1e6D + " ms" );
164+
165+ }catch (LoginException e )
166+ {
167+ System .out .println ("Refresh-token login failed after "
168+ + (System .nanoTime () - startTime ) / 1e6D + " ms" );
169+ throw e ;
170+ }
108171 }
109172
110173 private static MinecraftProfile getAccount (String email , String password )
@@ -117,14 +180,8 @@ private static MinecraftProfile getAccount(String email, String password)
117180 {
118181 String authCode = getAuthorizationCode (email , password );
119182 String msftAccessToken = getMicrosoftAccessToken (authCode );
120-
121- XBoxLiveToken xblToken = getXBLToken (msftAccessToken );
122- String xstsToken = getXSTSToken (xblToken .getToken ());
123-
124- String mcAccessToken =
125- getMinecraftAccessToken (xblToken .getUHS (), xstsToken );
126-
127- MinecraftProfile mcProfile = getMinecraftProfile (mcAccessToken );
183+ MinecraftProfile mcProfile =
184+ getAccountFromMicrosoftAccessToken (msftAccessToken );
128185
129186 System .out .println ("Login successful after "
130187 + (System .nanoTime () - startTime ) / 1e6D + " ms" );
@@ -141,6 +198,18 @@ private static MinecraftProfile getAccount(String email, String password)
141198 }
142199 }
143200
201+ private static MinecraftProfile getAccountFromMicrosoftAccessToken (
202+ String msftAccessToken ) throws LoginException
203+ {
204+ XBoxLiveToken xblToken = getXBLToken (msftAccessToken );
205+ String xstsToken = getXSTSToken (xblToken .getToken ());
206+
207+ String mcAccessToken =
208+ getMinecraftAccessToken (xblToken .getUHS (), xstsToken );
209+
210+ return getMinecraftProfile (mcAccessToken );
211+ }
212+
144213 private static String getAuthorizationCode (String email , String password )
145214 throws LoginException
146215 {
@@ -295,6 +364,50 @@ private static String getMicrosoftAccessToken(String authCode)
295364 }
296365 }
297366
367+ private static String getMicrosoftAccessTokenFromRefreshToken (
368+ String refreshToken ) throws LoginException
369+ {
370+ Map <String , String > postData = new HashMap <>();
371+ postData .put ("client_id" , CLIENT_ID );
372+ postData .put ("refresh_token" , refreshToken );
373+ postData .put ("grant_type" , "refresh_token" );
374+ postData .put ("redirect_uri" ,
375+ "https://login.live.com/oauth20_desktop.srf" );
376+ postData .put ("scope" , SCOPE_UNENCODED );
377+
378+ byte [] encodedDataBytes =
379+ urlEncodeMap (postData ).getBytes (StandardCharsets .UTF_8 );
380+
381+ try
382+ {
383+ HttpURLConnection connection =
384+ (HttpURLConnection )AUTH_TOKEN_URL .openConnection ();
385+
386+ connection .setRequestMethod ("POST" );
387+ connection .setRequestProperty ("Content-Type" ,
388+ "application/x-www-form-urlencoded; charset=UTF-8" );
389+ connection .setDoOutput (true );
390+
391+ System .out .println ("Refreshing Microsoft access token..." );
392+
393+ try (OutputStream out = connection .getOutputStream ())
394+ {
395+ out .write (encodedDataBytes );
396+ }
397+
398+ WsonObject json = JsonUtils .parseConnectionToObject (connection );
399+ return json .getString ("access_token" );
400+
401+ }catch (IOException e )
402+ {
403+ throw new LoginException ("Connection failed: " + e , e );
404+
405+ }catch (JsonException e )
406+ {
407+ throw new LoginException ("Server sent invalid JSON." , e );
408+ }
409+ }
410+
298411 private static XBoxLiveToken getXBLToken (String msftAccessToken )
299412 throws LoginException
300413 {
@@ -518,4 +631,12 @@ private static URL createURL(String url)
518631 throw new IllegalArgumentException (e );
519632 }
520633 }
634+
635+ private static void setSession (MinecraftProfile mcProfile )
636+ {
637+ User session = new User (mcProfile .getName (), mcProfile .getUUID (),
638+ mcProfile .getAccessToken (), Optional .empty (), Optional .empty ());
639+
640+ WurstClient .IMC .setWurstSession (session );
641+ }
521642}
0 commit comments