mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
Merge pull request #2971 from MCCTeam/copilot/modernize-authentication-module
This commit is contained in:
commit
3a5283285a
10 changed files with 215 additions and 162 deletions
|
|
@ -390,6 +390,8 @@ namespace MinecraftClient
|
|||
|
||||
//Asking the user to type in missing data such as Username and Password
|
||||
bool useBrowser = Config.Main.General.AccountType == LoginType.microsoft && Config.Main.General.Method == LoginMethod.browser;
|
||||
bool useDeviceCode = Config.Main.General.AccountType == LoginType.microsoft && Config.Main.General.Method == LoginMethod.mcc;
|
||||
bool skipPassword = useBrowser || useDeviceCode;
|
||||
if (string.IsNullOrWhiteSpace(InternalConfig.Account.Login) && !useBrowser)
|
||||
{
|
||||
ConsoleIO.WriteLine(ConsoleIO.BasicIO ? Translations.mcc_login_basic_io : Translations.mcc_login);
|
||||
|
|
@ -401,7 +403,7 @@ namespace MinecraftClient
|
|||
}
|
||||
}
|
||||
InternalConfig.Username = InternalConfig.Account.Login;
|
||||
if (string.IsNullOrWhiteSpace(InternalConfig.Account.Password) && !useBrowser &&
|
||||
if (string.IsNullOrWhiteSpace(InternalConfig.Account.Password) && !skipPassword &&
|
||||
(Config.Main.Advanced.SessionCache == CacheType.none || !SessionCache.Contains(ToLowerIfNeed(InternalConfig.Account.Login))))
|
||||
{
|
||||
RequestPassword();
|
||||
|
|
@ -475,7 +477,7 @@ namespace MinecraftClient
|
|||
|
||||
if (result != ProtocolHandler.LoginResult.Success
|
||||
&& string.IsNullOrWhiteSpace(InternalConfig.Account.Password)
|
||||
&& !(Config.Main.General.AccountType == LoginType.microsoft && Config.Main.General.Method == LoginMethod.browser))
|
||||
&& !(Config.Main.General.AccountType == LoginType.microsoft))
|
||||
RequestPassword();
|
||||
}
|
||||
else ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_session_valid, session.PlayerName));
|
||||
|
|
@ -594,7 +596,7 @@ namespace MinecraftClient
|
|||
}
|
||||
|
||||
if ((Config.Main.General.AccountType == LoginType.microsoft || Config.Main.General.AccountType == LoginType.yggdrasil)
|
||||
&& (InternalConfig.Account.Password != "-" || Config.Main.General.Method == LoginMethod.browser)
|
||||
&& InternalConfig.Account.Password != "-"
|
||||
&& Config.Signature.LoginWithSecureProfile
|
||||
&& protocolversion >= 759 /* 1.19 and above */
|
||||
&& !string.IsNullOrWhiteSpace(session.ID))
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using static MinecraftClient.Settings;
|
||||
using static MinecraftClient.Settings.MainConfigHelper.MainConfig.GeneralConfig;
|
||||
using System.Threading;
|
||||
|
||||
namespace MinecraftClient.Protocol
|
||||
{
|
||||
|
|
@ -16,6 +14,7 @@ namespace MinecraftClient.Protocol
|
|||
private static readonly string clientId = "54473e32-df8f-42e9-a649-9419b0dab9d3";
|
||||
private static readonly string signinUrl = string.Format("https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id={0}&response_type=code&redirect_uri=https%3A%2F%2Fmccteam.github.io%2Fredirect.html&scope=XboxLive.signin%20offline_access%20openid%20email&prompt=select_account&response_mode=fragment", clientId);
|
||||
private static readonly string tokenUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
|
||||
private static readonly string deviceCodeUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode";
|
||||
|
||||
public static string SignInUrl { get { return signinUrl; } }
|
||||
|
||||
|
|
@ -53,6 +52,121 @@ namespace MinecraftClient.Protocol
|
|||
return RequestToken(postData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiate the OAuth 2.0 device code flow.
|
||||
/// Returns a device code response containing the user code and verification URI.
|
||||
/// </summary>
|
||||
/// <returns>Device code response for user to complete authentication</returns>
|
||||
public static DeviceCodeResponse RequestDeviceCode()
|
||||
{
|
||||
string postData = string.Format("client_id={0}&scope=XboxLive.signin%20offline_access%20openid%20email", clientId);
|
||||
|
||||
var request = new ProxiedWebRequest(deviceCodeUrl)
|
||||
{
|
||||
UserAgent = "MCC/" + Program.Version
|
||||
};
|
||||
var response = request.Post("application/x-www-form-urlencoded", postData);
|
||||
var jsonData = Json.ParseJson(response.Body);
|
||||
|
||||
if (jsonData?["error"] is not null)
|
||||
{
|
||||
throw new Exception(jsonData["error_description"]!.GetStringValue());
|
||||
}
|
||||
|
||||
return new DeviceCodeResponse()
|
||||
{
|
||||
DeviceCode = jsonData!["device_code"]!.GetStringValue(),
|
||||
UserCode = jsonData["user_code"]!.GetStringValue(),
|
||||
VerificationUri = jsonData["verification_uri"]!.GetStringValue(),
|
||||
ExpiresIn = int.Parse(jsonData["expires_in"]!.GetStringValue(), NumberStyles.Any, CultureInfo.CurrentCulture),
|
||||
Interval = int.Parse(jsonData["interval"]!.GetStringValue(), NumberStyles.Any, CultureInfo.CurrentCulture),
|
||||
Message = jsonData["message"]!.GetStringValue()
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Poll the token endpoint until the user completes device code authentication.
|
||||
/// Handles authorization_pending, slow_down, and expiration.
|
||||
/// </summary>
|
||||
/// <param name="deviceCode">Device code from <see cref="RequestDeviceCode"/></param>
|
||||
/// <param name="expiresIn">Expiration time in seconds</param>
|
||||
/// <param name="interval">Polling interval in seconds</param>
|
||||
/// <returns>Login response with access token and refresh token</returns>
|
||||
public static LoginResponse PollDeviceCodeToken(string deviceCode, int expiresIn, int interval)
|
||||
{
|
||||
// Per OAuth 2.0 device code spec, server may respond with "slow_down" requiring
|
||||
// the client to increase its polling interval by this amount
|
||||
const int SlowDownIncrementSeconds = 5;
|
||||
|
||||
string postData = string.Format(
|
||||
"client_id={0}&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code={1}",
|
||||
clientId, deviceCode);
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
int pollInterval = interval;
|
||||
|
||||
while (stopwatch.Elapsed.TotalSeconds < expiresIn)
|
||||
{
|
||||
Thread.Sleep(pollInterval * 1000);
|
||||
|
||||
var request = new ProxiedWebRequest(tokenUrl)
|
||||
{
|
||||
UserAgent = "MCC/" + Program.Version
|
||||
};
|
||||
var response = request.Post("application/x-www-form-urlencoded", postData);
|
||||
var jsonData = Json.ParseJson(response.Body);
|
||||
|
||||
if (jsonData?["error"] is not null)
|
||||
{
|
||||
string error = jsonData["error"]!.GetStringValue();
|
||||
|
||||
if (error == "authorization_pending")
|
||||
{
|
||||
// User hasn't completed auth yet, keep polling
|
||||
continue;
|
||||
}
|
||||
else if (error == "slow_down")
|
||||
{
|
||||
// Server asked us to slow down
|
||||
pollInterval += SlowDownIncrementSeconds;
|
||||
continue;
|
||||
}
|
||||
else if (error == "expired_token")
|
||||
{
|
||||
throw new Exception("Device code expired. Please try again.");
|
||||
}
|
||||
else if (error == "authorization_declined")
|
||||
{
|
||||
throw new Exception("Authorization was declined by the user.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(jsonData["error_description"]!.GetStringValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Success - parse the token response
|
||||
string accessToken = jsonData!["access_token"]!.GetStringValue();
|
||||
string refreshToken = jsonData["refresh_token"]!.GetStringValue();
|
||||
int tokenExpiresIn = int.Parse(jsonData["expires_in"]!.GetStringValue(), NumberStyles.Any, CultureInfo.CurrentCulture);
|
||||
|
||||
// Extract email from JWT id_token
|
||||
string payload = JwtPayloadDecode.GetPayload(jsonData["id_token"]!.GetStringValue());
|
||||
var jsonPayload = Json.ParseJson(payload);
|
||||
string email = jsonPayload!["email"]!.GetStringValue();
|
||||
|
||||
return new LoginResponse()
|
||||
{
|
||||
Email = email,
|
||||
AccessToken = accessToken,
|
||||
RefreshToken = refreshToken,
|
||||
ExpiresIn = tokenExpiresIn
|
||||
};
|
||||
}
|
||||
|
||||
throw new Exception("Device code authentication timed out.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform request to obtain access token by code or by refresh token
|
||||
/// </summary>
|
||||
|
|
@ -70,13 +184,13 @@ namespace MinecraftClient.Protocol
|
|||
// Error handling
|
||||
if (jsonData?["error"] is not null)
|
||||
{
|
||||
throw new Exception(jsonData["error_description"].GetStringValue());
|
||||
throw new Exception(jsonData["error_description"]!.GetStringValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
string accessToken = jsonData!["access_token"]!.GetStringValue();
|
||||
string refreshToken = jsonData["refresh_token"]!.GetStringValue();
|
||||
int expiresIn = int.Parse(jsonData["expires_in"].GetStringValue(), NumberStyles.Any, CultureInfo.CurrentCulture);
|
||||
int expiresIn = int.Parse(jsonData["expires_in"]!.GetStringValue(), NumberStyles.Any, CultureInfo.CurrentCulture);
|
||||
|
||||
// Extract email from JWT
|
||||
string payload = JwtPayloadDecode.GetPayload(jsonData["id_token"]!.GetStringValue());
|
||||
|
|
@ -132,132 +246,25 @@ namespace MinecraftClient.Protocol
|
|||
public string RefreshToken;
|
||||
public int ExpiresIn;
|
||||
}
|
||||
|
||||
public struct DeviceCodeResponse
|
||||
{
|
||||
public string DeviceCode;
|
||||
public string UserCode;
|
||||
public string VerificationUri;
|
||||
public int ExpiresIn;
|
||||
public int Interval;
|
||||
public string Message;
|
||||
}
|
||||
}
|
||||
|
||||
static class XboxLive
|
||||
{
|
||||
private static readonly string authorize = "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";
|
||||
private static readonly string xbl = "https://user.auth.xboxlive.com/user/authenticate";
|
||||
private static readonly string xsts = "https://xsts.auth.xboxlive.com/xsts/authorize";
|
||||
|
||||
private static readonly string userAgent = "Mozilla/5.0 (XboxReplay; XboxLiveAuth/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36";
|
||||
|
||||
private static readonly Regex ppft = new("sFTTag:'.*value=\"(.*)\"\\/>'");
|
||||
private static readonly Regex urlPost = new("urlPost:'(.+?(?=\'))");
|
||||
private static readonly Regex confirm = new("identity\\/confirm");
|
||||
private static readonly Regex invalidAccount = new("Sign in to", RegexOptions.IgnoreCase);
|
||||
private static readonly Regex twoFA = new("Help us protect your account", RegexOptions.IgnoreCase);
|
||||
|
||||
public static string SignInUrl { get { return authorize; } }
|
||||
|
||||
/// <summary>
|
||||
/// Pre-authentication
|
||||
/// </summary>
|
||||
/// <remarks>This step is to get the login page for later use</remarks>
|
||||
/// <returns></returns>
|
||||
public static PreAuthResponse PreAuth()
|
||||
{
|
||||
var request = new ProxiedWebRequest(authorize)
|
||||
{
|
||||
UserAgent = userAgent
|
||||
};
|
||||
var response = request.Get();
|
||||
|
||||
string html = response.Body;
|
||||
|
||||
string PPFT = ppft.Match(html).Groups[1].Value;
|
||||
string urlPost = XboxLive.urlPost.Match(html).Groups[1].Value;
|
||||
|
||||
if (string.IsNullOrEmpty(PPFT) || string.IsNullOrEmpty(urlPost))
|
||||
{
|
||||
throw new Exception("Fail to extract PPFT or urlPost");
|
||||
}
|
||||
//Console.WriteLine("PPFT: {0}", PPFT);
|
||||
//Console.WriteLine();
|
||||
//Console.WriteLine("urlPost: {0}", urlPost);
|
||||
|
||||
return new PreAuthResponse()
|
||||
{
|
||||
UrlPost = urlPost,
|
||||
PPFT = PPFT,
|
||||
Cookie = response.Cookies
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform login request
|
||||
/// </summary>
|
||||
/// <remarks>This step is to send the login request by using the PreAuth response</remarks>
|
||||
/// <param name="email">Microsoft account email</param>
|
||||
/// <param name="password">Account password</param>
|
||||
/// <param name="preAuth"></param>
|
||||
/// <returns></returns>
|
||||
public static Microsoft.LoginResponse UserLogin(string email, string password, PreAuthResponse preAuth)
|
||||
{
|
||||
var request = new ProxiedWebRequest(preAuth.UrlPost, preAuth.Cookie)
|
||||
{
|
||||
UserAgent = userAgent
|
||||
};
|
||||
|
||||
string postData = "login=" + Uri.EscapeDataString(email)
|
||||
+ "&loginfmt=" + Uri.EscapeDataString(email)
|
||||
+ "&passwd=" + Uri.EscapeDataString(password)
|
||||
+ "&PPFT=" + Uri.EscapeDataString(preAuth.PPFT);
|
||||
|
||||
var response = request.Post("application/x-www-form-urlencoded", postData);
|
||||
|
||||
if (Settings.Config.Logging.DebugMessages)
|
||||
{
|
||||
ConsoleIO.WriteLine(response.ToString());
|
||||
}
|
||||
|
||||
if (response.StatusCode >= 300 && response.StatusCode <= 399)
|
||||
{
|
||||
string url = response.Headers.Get("Location")!;
|
||||
string hash = url.Split('#')[1];
|
||||
|
||||
var request2 = new ProxiedWebRequest(url);
|
||||
var response2 = request2.Get();
|
||||
|
||||
if (response2.StatusCode != 200)
|
||||
{
|
||||
throw new Exception("Authentication failed");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(hash))
|
||||
{
|
||||
throw new Exception("Cannot extract access token");
|
||||
}
|
||||
var dict = Request.ParseQueryString(hash);
|
||||
|
||||
//foreach (var pair in dict)
|
||||
//{
|
||||
// Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
|
||||
//}
|
||||
|
||||
return new Microsoft.LoginResponse()
|
||||
{
|
||||
Email = email,
|
||||
AccessToken = dict["access_token"],
|
||||
RefreshToken = dict["refresh_token"],
|
||||
ExpiresIn = int.Parse(dict["expires_in"], NumberStyles.Any, CultureInfo.CurrentCulture)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (twoFA.IsMatch(response.Body))
|
||||
{
|
||||
// TODO: Handle 2FA
|
||||
throw new Exception("2FA enabled but not supported yet. Use browser sign-in method or try to disable 2FA in Microsoft account settings");
|
||||
}
|
||||
else if (invalidAccount.IsMatch(response.Body))
|
||||
{
|
||||
throw new Exception("Invalid credentials. Check your credentials");
|
||||
}
|
||||
else throw new Exception("Unexpected response. Check your credentials. Response code: " + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xbox Live Authenticate
|
||||
/// </summary>
|
||||
|
|
@ -272,13 +279,8 @@ namespace MinecraftClient.Protocol
|
|||
};
|
||||
request.Headers.Add("x-xbl-contract-version", "0");
|
||||
|
||||
var accessToken = loginResponse.AccessToken;
|
||||
if (Config.Main.General.Method == LoginMethod.browser)
|
||||
{
|
||||
// Our own client ID must have d= in front of the token or HTTP status 400
|
||||
// "Stolen" client ID must not have d= in front of the token or HTTP status 400
|
||||
accessToken = "d=" + accessToken;
|
||||
}
|
||||
// OAuth tokens from our own client ID require "d=" prefix for XBL authentication
|
||||
var accessToken = "d=" + loginResponse.AccessToken;
|
||||
|
||||
string payload = "{"
|
||||
+ "\"Properties\": {"
|
||||
|
|
@ -297,8 +299,6 @@ namespace MinecraftClient.Protocol
|
|||
if (response.StatusCode == 200)
|
||||
{
|
||||
string jsonString = response.Body;
|
||||
//Console.WriteLine(jsonString);
|
||||
|
||||
var json = Json.ParseJson(jsonString);
|
||||
string token = json!["Token"]!.GetStringValue();
|
||||
string userHash = json["DisplayClaims"]!["xui"]![0]!["uhs"]!.GetStringValue();
|
||||
|
|
@ -317,7 +317,7 @@ namespace MinecraftClient.Protocol
|
|||
/// <summary>
|
||||
/// XSTS Authenticate
|
||||
/// </summary>
|
||||
/// <remarks>(Don't ask me what is XSTS, I DONT KNOW)</remarks>
|
||||
/// <remarks>Xbox Secure Token Service - exchanges XBL token for a service-specific XSTS token</remarks>
|
||||
/// <param name="xblResponse"></param>
|
||||
/// <returns></returns>
|
||||
public static XSTSAuthenticateResponse XSTSAuthenticate(XblAuthenticateResponse xblResponse)
|
||||
|
|
@ -378,13 +378,6 @@ namespace MinecraftClient.Protocol
|
|||
}
|
||||
}
|
||||
|
||||
public struct PreAuthResponse
|
||||
{
|
||||
public string UrlPost;
|
||||
public string PPFT;
|
||||
public NameValueCollection Cookie;
|
||||
}
|
||||
|
||||
public struct XblAuthenticateResponse
|
||||
{
|
||||
public string Token;
|
||||
|
|
|
|||
|
|
@ -776,20 +776,27 @@ namespace MinecraftClient.Protocol
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sign-in to Microsoft Account without using browser. Only works if 2FA is disabled.
|
||||
/// Might not work well in some rare cases.
|
||||
/// Sign-in to Microsoft Account using OAuth 2.0 device code flow.
|
||||
/// Supports accounts with 2FA enabled.
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="email">Email hint (unused in device code flow, kept for API compatibility)</param>
|
||||
/// <param name="password">Password (unused in device code flow, kept for API compatibility)</param>
|
||||
/// <param name="session"></param>
|
||||
/// <returns></returns>
|
||||
private static LoginResult MicrosoftMCCLogin(string email, string password, out SessionToken session)
|
||||
{
|
||||
try
|
||||
{
|
||||
var msaResponse = XboxLive.UserLogin(email, password, XboxLive.PreAuth());
|
||||
// Remove refresh token for MCC sign method
|
||||
msaResponse.RefreshToken = string.Empty;
|
||||
var deviceCode = Microsoft.RequestDeviceCode();
|
||||
|
||||
ConsoleIO.WriteLineFormatted(string.Format(Translations.mcc_device_code_prompt, deviceCode.VerificationUri, deviceCode.UserCode));
|
||||
|
||||
// Try to open the verification URL in the user's browser
|
||||
Microsoft.OpenBrowser(deviceCode.VerificationUri);
|
||||
|
||||
ConsoleIO.WriteLineFormatted(Translations.mcc_device_code_waiting);
|
||||
|
||||
var msaResponse = Microsoft.PollDeviceCodeToken(deviceCode.DeviceCode, deviceCode.ExpiresIn, deviceCode.Interval);
|
||||
return MicrosoftLogin(msaResponse, out session);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -801,7 +808,7 @@ namespace MinecraftClient.Protocol
|
|||
ConsoleIO.WriteLineFormatted("§c" + e.StackTrace);
|
||||
}
|
||||
|
||||
return LoginResult.WrongPassword; // Might not always be wrong password
|
||||
return LoginResult.OtherError;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1922,7 +1922,7 @@ namespace MinecraftClient {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once..
|
||||
/// Looks up a localized string similar to Microsoft Account sign-in method: "mcc" (device code, supports 2FA) OR "browser" (manual browser login)..
|
||||
/// </summary>
|
||||
internal static string Main_General_method {
|
||||
get {
|
||||
|
|
|
|||
|
|
@ -724,7 +724,7 @@ Usage examples: "/tell <mybot> connect Server1", "/connect Server2"</value
|
|||
<value>The address of the game server, "Host" can be filled in with domain name or IP address. (The "Port" field can be deleted, it will be resolved automatically)</value>
|
||||
</data>
|
||||
<data name="Main.General.method" xml:space="preserve">
|
||||
<value>Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once.</value>
|
||||
<value>Microsoft Account sign-in method: "mcc" (device code, supports 2FA) OR "browser" (manual browser login).</value>
|
||||
</data>
|
||||
<data name="Main.General.server_info" xml:space="preserve">
|
||||
<value>Account type: "mojang" OR "microsoft" OR "yggdrasil". Also affects interactive login in console.</value>
|
||||
|
|
|
|||
|
|
@ -5498,6 +5498,24 @@ namespace MinecraftClient {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to To sign in, open {0} in your browser and enter the code: {1}.
|
||||
/// </summary>
|
||||
internal static string mcc_device_code_prompt {
|
||||
get {
|
||||
return ResourceManager.GetString("mcc.device_code_prompt", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Waiting for authentication to complete....
|
||||
/// </summary>
|
||||
internal static string mcc_device_code_waiting {
|
||||
get {
|
||||
return ResourceManager.GetString("mcc.device_code_waiting", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Login failed :.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1851,6 +1851,12 @@ You can use "/chunk status {0:0.0} {1:0.0} {2:0.0}" to check the chunk loading s
|
|||
<data name="mcc.connecting" xml:space="preserve">
|
||||
<value>Connecting to {0}...</value>
|
||||
</data>
|
||||
<data name="mcc.device_code_prompt" xml:space="preserve">
|
||||
<value>To sign in, open {0} in your browser and enter the code: §e{1}</value>
|
||||
</data>
|
||||
<data name="mcc.device_code_waiting" xml:space="preserve">
|
||||
<value>Waiting for authentication to complete...</value>
|
||||
</data>
|
||||
<data name="mcc.disconnect.login" xml:space="preserve">
|
||||
<value>Login failed :</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ It was originally made by [ORelio](https://github.com/ORelio) in 2012 on the [Mi
|
|||
- [Get alerted on certain keywords](chat-bots.md#alerts)
|
||||
- [Auto Respond](chat-bots.md#auto-respond)
|
||||
|
||||
- Microsoft account authentication with 2FA support (OAuth 2.0 device code flow)
|
||||
- [Anti AFK](chat-bots.md#anti-afk)
|
||||
- [Auto Relog](chat-bots.md#auto-relog)
|
||||
- [Script Scheduler](chat-bots.md#script-scheduler)
|
||||
|
|
|
|||
|
|
@ -67,17 +67,33 @@ Coordinate = { x = 145, y = 64, z = 2045 }
|
|||
|
||||
- **Description:**
|
||||
|
||||
This setting is where you need to provide your in-game name (for offline accounts) or email for Microsoft accounts (Mojang accounts do not work anymore) and your password (if using an offline account, use `-` for the password).
|
||||
This setting is where you provide your account login information.
|
||||
|
||||
For **Microsoft accounts**, set `Login` to your Microsoft email. You do not need to provide a password because MCC uses the OAuth 2.0 device code flow for authentication (you sign in through your browser, with full 2FA support).
|
||||
|
||||
For **offline accounts**, set `Login` to your desired in-game name and `Password` to `-`.
|
||||
|
||||
For **Yggdrasil accounts**, set `Login` and `Password` to the credentials for your authlib server.
|
||||
|
||||
- **Format:**
|
||||
|
||||
`Account = { Login = "<email>", Password = "<password>" }`
|
||||
`Account = { Login = "<email>" }`
|
||||
|
||||
- **Type:** `inline table`
|
||||
|
||||
- **Example:**
|
||||
- **Examples:**
|
||||
|
||||
`Account = { Login = "some.random.player@gmail.com", Password = "myEpicPassword123" }`
|
||||
Microsoft account (password not needed):
|
||||
|
||||
```
|
||||
Account = { Login = "player@example.com" }
|
||||
```
|
||||
|
||||
Offline account:
|
||||
|
||||
```
|
||||
Account = { Login = "Steve", Password = "-" }
|
||||
```
|
||||
|
||||
#### `Server`
|
||||
|
||||
|
|
@ -131,7 +147,7 @@ Coordinate = { x = 145, y = 64, z = 2045 }
|
|||
|
||||
- **Description:**
|
||||
|
||||
This setting is where you define the way you will sign in with your Microsoft account, available options are `mcc` and `browser`.
|
||||
This setting is where you define the way you will sign in with your Microsoft account, available options are `mcc` and `browser`. The `mcc` method uses the OAuth 2.0 device code flow: MCC will display a code and a URL, and you complete the sign-in (including 2FA) in your browser. The `browser` method opens a sign-in page in your browser and you paste the resulting code back into MCC.
|
||||
|
||||
- **Type:** `string`
|
||||
|
||||
|
|
|
|||
|
|
@ -121,11 +121,20 @@ MinecraftClient.exe --section.setting=value [--other settings]
|
|||
MinecraftClient.exe <settings-file.ini> [--other settings]
|
||||
```
|
||||
|
||||
<div class="custom-container tip"><p class="custom-container-title">Tip</p>
|
||||
|
||||
**Microsoft accounts use the OAuth 2.0 device code flow and do not require a password on the command line. MCC will display a code and a URL for you to sign in through your browser (with full 2FA support). You can simply omit the password or use `""` as a placeholder.**
|
||||
|
||||
</div>
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Logging in as a user: notch, with a password: password123 onto a server with the ip: mc.someserver.com:25565
|
||||
MinecraftClient.exe notch password123 mc.someserver.com:25565
|
||||
# Microsoft account: connect to a server (you will sign in via device code in your browser)
|
||||
MinecraftClient.exe player@example.com "" mc.someserver.com:25565
|
||||
|
||||
# Offline account: connect with a chosen username
|
||||
MinecraftClient.exe Steve - mc.someserver.com:25565
|
||||
|
||||
# Overriding a setting from MinecraftClient.ini using a command-line parameter
|
||||
MinecraftClient.exe --debugmessages=false
|
||||
|
|
@ -150,7 +159,7 @@ MinecraftClient.exe <login> <password> <server>
|
|||
|
||||
- This will automatically connect you to the chosen server.
|
||||
- You may omit password and/or server to specify e.g. only the login
|
||||
- To specify a server but ask password interactively, use `""` as password.
|
||||
- For Microsoft accounts, password is not required (device code flow is used). Use `""` as a placeholder if you need to specify a server.
|
||||
- To specify offline mode with no password, use `-` as password.
|
||||
|
||||
```bash
|
||||
|
|
@ -165,7 +174,8 @@ MinecraftClient.exe <myconfig.ini>
|
|||
```
|
||||
|
||||
- This will load the specified configuration file
|
||||
- If the file contains login / password / server ip, it will automatically connect.
|
||||
- If the file contains login / server ip, it will automatically connect.
|
||||
- For Microsoft accounts, authentication happens through the device code flow (no password needed in the file).
|
||||
|
||||
```bash
|
||||
MinecraftClient.exe --setting=value [--other settings]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue