Skip to content
This repository was archived by the owner on Mar 14, 2026. It is now read-only.

Commit 47f1eab

Browse files
committed
feat: minecraft-auth partial support
1 parent 9845ba8 commit 47f1eab

3 files changed

Lines changed: 131 additions & 56 deletions

File tree

crates/core/src/auth/microsoft.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,22 +168,22 @@ pub fn ouath_token(
168168
code: Option<&str>,
169169
client_id: &str,
170170
scope: &str,
171-
port: u16,
172-
client_secret: &str,
171+
redirect_uri: String,
172+
client_secret: Option<&str>,
173173
) -> impl AsyncSendSync<Result<OuathToken, AuthErrors>> {
174174
let url = format!("https://login.microsoftonline.com/consumers/oauth2/v2.0/token");
175-
let mut body = format!(
176-
"client_id={}&scope={}&client_secret={}",
177-
client_id, scope, client_secret
178-
);
175+
let mut body = format!("client_id={}&scope={}", client_id, scope);
176+
177+
if let Some(secret) = client_secret {
178+
body.push_str(&format!("&client_secret={}", secret))
179+
}
179180

180181
if let Some(token) = refresh_token {
181182
body.push_str(&format!(
182183
"&grant_type=refresh_token&refresh_token={}",
183184
token
184185
));
185186
} else if let Some(auth_code) = code {
186-
let redirect_uri = format!("http://localhost:{}", port);
187187
body.push_str(&format!(
188188
"&grant_type=authorization_code&code={}&redirect_uri={}",
189189
auth_code, redirect_uri

crates/minecraft-essentails/src/lib.rs

Lines changed: 118 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl Oauth {
112112
let mut builder = AuthenticationBuilder::builder();
113113
builder
114114
.port(self.port)
115-
.client_id(&self.client_id)
115+
.client_id(Some(&self.client_id))
116116
.of_type(AuthType::Oauth);
117117
let auth_info = builder
118118
.get_info()
@@ -144,10 +144,10 @@ impl Oauth {
144144
AuthenticationBuilder::builder()
145145
.bedrockrel(Some(bedrock_relm))
146146
.of_type(AuthType::Oauth)
147-
.client_secret(client_secret)
148-
.client_id(&self.client_id)
147+
.client_secret(Some(client_secret))
148+
.client_id(Some(&self.client_id))
149149
.port(Some(self.port))
150-
.launch()
150+
.launch(None, None)
151151
.await
152152
}
153153

@@ -216,6 +216,11 @@ pub enum AuthType {
216216
/// This is used for refreshing your token with Minecraft.
217217
#[cfg(feature = "auth")]
218218
Refresh,
219+
220+
/// Minecraft authentification method
221+
///
222+
/// Uses Minecraft Auth menthod (habdy if you want the minecraft background)
223+
Minecraft,
219224
}
220225

221226
/// Represents a builder for authentication configurations.
@@ -226,10 +231,10 @@ pub enum AuthType {
226231
#[cfg(feature = "auth")]
227232
pub struct AuthenticationBuilder {
228233
auth_type: AuthType,
229-
client_id: String,
234+
client_id: Option<String>,
230235
scope: Option<String>,
231-
port: u16,
232-
client_secrect: String,
236+
port: Option<u16>,
237+
client_secret: Option<String>,
233238
bedrockrel: bool,
234239
refresh_token: Option<String>,
235240
}
@@ -244,6 +249,8 @@ pub struct AuthInfo {
244249
pub device_code: Option<CodeResponse>,
245250
/// OAuth URL that you will recive based on AuthType::OAuth.
246251
pub ouath_url: Option<String>,
252+
/// Redirect URL: Only needed when using minecraft auth
253+
pub redirect_url: Option<String>,
247254
}
248255

249256
#[cfg(feature = "auth")]
@@ -252,10 +259,10 @@ impl AuthenticationBuilder {
252259
pub fn builder() -> Self {
253260
Self {
254261
auth_type: AuthType::Oauth,
255-
client_id: "".to_string(),
262+
client_id: None,
256263
scope: Some(SCOPE.to_string()),
257-
port: 8000,
258-
client_secrect: "".to_string(),
264+
port: Some(8000),
265+
client_secret: None,
259266
bedrockrel: false,
260267
refresh_token: None,
261268
}
@@ -270,24 +277,28 @@ impl AuthenticationBuilder {
270277
}
271278

272279
/// Client ID from your application Required for `OAuth` & `DeviceCode`.
273-
pub fn client_id(&mut self, client_id: &str) -> &mut Self {
274-
self.client_id = client_id.to_string();
280+
pub fn client_id(&mut self, client_id: Option<&str>) -> &mut Self {
281+
if client_id.is_some() {
282+
self.client_id = client_id.map(|id| id.to_string());
283+
}
275284
self
276285
}
277286

278287
/// Port for the Temporary https Required for `OAuth``.
279288
pub fn port<T: Optional<u16>>(&mut self, port: T) -> &mut Self {
280289
let port = match port.into() {
281-
Some(port) => port,
282-
None => 8000,
290+
Some(port) => Some(port),
291+
None => None,
283292
};
284293
self.port = port;
285294
self
286295
}
287296

288297
/// Client Secret from your application Required for `OAuth` & `DeviceCode`.
289-
pub fn client_secret(&mut self, client_secret: &str) -> &mut Self {
290-
self.client_secrect = client_secret.to_string();
298+
pub fn client_secret(&mut self, client_secret: Option<&str>) -> &mut Self {
299+
if client_secret.is_some() {
300+
self.client_secret = client_secret.map(|secret| secret.to_string());
301+
}
291302
self
292303
}
293304

@@ -324,36 +335,63 @@ impl AuthenticationBuilder {
324335
/// Gets the code for device code method
325336
pub async fn get_info(&mut self) -> AuthInfo {
326337
let client = Client::new();
327-
if self.auth_type == AuthType::DeviceCode {
328-
let code = device_authentication_code(client, &self.client_id)
329-
.await
330-
.unwrap();
331-
AuthInfo {
332-
device_code: Some(code),
333-
ouath_url: None,
338+
339+
match self.auth_type {
340+
AuthType::DeviceCode => {
341+
let client_id = &self.client_id.clone().expect("EXPECTED CLIENT_ID");
342+
let code = device_authentication_code(client, client_id).await.unwrap();
343+
AuthInfo {
344+
device_code: Some(code),
345+
ouath_url: None,
346+
redirect_url: None,
347+
}
334348
}
335-
} else {
336-
let url = format!(
337-
"https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize/?client_id={}&response_type=code&redirect_uri=http://localhost:{}&response_mode=query&scope={}&state=12345",
338-
self.client_id, self.port, SCOPE
339-
);
340-
AuthInfo {
341-
device_code: None,
342-
ouath_url: Some(url),
349+
AuthType::Oauth | AuthType::Refresh => {
350+
let client_id = &self.client_id.clone().expect("EXPECTED CLIENT_ID");
351+
let url = format!(
352+
"https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize/?client_id={}&response_type=code&redirect_uri=http://localhost:{}&response_mode=query&scope={}&state=12345",
353+
client_id,
354+
self.port.expect("EXPECTED PORT"),
355+
self.scope.clone().expect("Expected Scope")
356+
);
357+
AuthInfo {
358+
device_code: None,
359+
ouath_url: Some(url),
360+
redirect_url: None,
361+
}
362+
}
363+
AuthType::Minecraft => {
364+
let redirect_url = "https://login.live.com/oauth20_desktop.srf";
365+
let url = format!(
366+
"https://login.live.com/oauth20_authorize.srf?client_id=00000000402B5328&redirect_uri={}&response_type=code&scope=service::user.auth.xboxlive.com::MBI_SSL",
367+
redirect_url
368+
);
369+
370+
AuthInfo {
371+
device_code: None,
372+
ouath_url: Some(url),
373+
redirect_url: Some(redirect_url.to_string()),
374+
}
343375
}
344376
}
345377
}
346378

347379
/// Launchs the authentication process.
348-
pub async fn launch(&mut self) -> Result<CustomAuthData, Box<dyn std::error::Error>> {
380+
pub async fn launch(
381+
&mut self,
382+
code: Option<&str>,
383+
redirect_url: Option<String>,
384+
) -> Result<CustomAuthData, Box<dyn std::error::Error>> {
349385
dbg!(&self.auth_type, &self.client_id);
350386
let client = Client::new();
351387

352388
match self.auth_type {
353389
AuthType::Oauth => {
354-
dbg!(&self.client_secrect, self.port);
355-
print!("{}", self.client_id);
356-
let server = ouath(self.port)?.await?;
390+
dbg!(&self.client_secret, self.port, &self.client_secret);
391+
let client_id = &self.client_id.clone().expect("EXPECTED CLIENT_ID");
392+
let client_secret = &self.client_secret.clone().expect("EXPECTED CLIENT_ID");
393+
394+
let server = ouath(self.port.expect("EXPECTED PORT"))?.await?;
357395
let server_token = ouath_token(
358396
client.clone(),
359397
None,
@@ -363,10 +401,10 @@ impl AuthenticationBuilder {
363401
.expect("\x1b[31mXbox Expected code.\x1b[0m")
364402
.as_str(),
365403
),
366-
&self.client_id,
404+
client_id,
367405
self.scope.as_deref().unwrap_or_default(),
368-
self.port,
369-
&self.client_secrect,
406+
format!("https://localhost:{}", self.port.expect("EXPECTED PORT")),
407+
Some(client_secret),
370408
)
371409
.await?;
372410
let xbl = xbl(client.clone(), &server_token.access_token).await?;
@@ -384,10 +422,12 @@ impl AuthenticationBuilder {
384422
}
385423
}
386424
AuthType::DeviceCode => {
425+
let client_id = &self.client_id.clone().expect("EXPECTED CLIENT_ID");
426+
387427
print!("{} \n Status: WIP (Work In Progress)", EXPERIMENTAL_MESSAGE);
388-
let code = device_authentication_code(client.clone(), &self.client_id).await?;
428+
let code = device_authentication_code(client.clone(), client_id).await?;
389429
let code_token =
390-
authenticate_device(client.clone(), &code.device_code, &self.client_id).await?;
430+
authenticate_device(client.clone(), &code.device_code, client_id).await?;
391431
let xbl = xbl(client.clone(), &code_token.token).await?;
392432
let xts = xsts(client.clone(), &xbl.token, self.bedrockrel).await?;
393433

@@ -403,6 +443,9 @@ impl AuthenticationBuilder {
403443
}
404444
}
405445
AuthType::Refresh => {
446+
let client_id = &self.client_id.clone().expect("EXPECTED CLIENT_ID");
447+
let client_secret = &self.client_secret.clone().expect("EXPECTED CLIENT_ID");
448+
406449
if self.refresh_token == None {
407450
return Err(Box::new(errors::AuthErrors::AuthenticationFailure(
408451
"Missing Refresh Token".to_string(),
@@ -412,10 +455,42 @@ impl AuthenticationBuilder {
412455
client.clone(),
413456
self.refresh_token.clone(),
414457
None,
415-
&self.client_id,
458+
client_id,
416459
self.scope.as_deref().unwrap_or_default(),
417-
self.port,
418-
&self.client_secrect,
460+
if self.port.is_some() {
461+
format!("https://localhost:{}", self.port.expect("EXPECTED PORT"))
462+
} else {
463+
redirect_url.expect("EXPECTED REDIRECT URL")
464+
},
465+
Some(client_secret),
466+
)
467+
.await?;
468+
let xbl = xbl(client.clone(), &server_token.access_token).await?;
469+
let xts = xsts(client.clone(), &xbl.token, self.bedrockrel).await?;
470+
471+
if self.bedrockrel {
472+
Ok(CustomAuthData {
473+
access_token: None,
474+
uuid: None,
475+
expires_in: 0,
476+
xts_token: Some(xts.token),
477+
})
478+
} else {
479+
Ok(bearer_token(client, &xbl.display_claims.xui[0].uhs, &xts.token).await?)
480+
}
481+
}
482+
AuthType::Minecraft => {
483+
dbg!(self.port);
484+
let client_id = &"00000000402B5328".to_string();
485+
486+
let server_token = ouath_token(
487+
client.clone(),
488+
None,
489+
code,
490+
client_id,
491+
"service::user.auth.xboxlive.com::MBI_SSL",
492+
"https://login.live.com/oauth20_token.srf".to_string(),
493+
None,
419494
)
420495
.await?;
421496
let xbl = xbl(client.clone(), &server_token.access_token).await?;

crates/minecraft-essentails/src/main.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clap::Parser;
2+
use cwd::{Cli, Commands, DeviceCodeArgs, OauthArgs};
23
use minecraft_essentials::{AuthType, AuthenticationBuilder};
3-
use cwd::{Commands, Cli, DeviceCodeArgs, OauthArgs};
44

55
mod cwd;
66

@@ -20,14 +20,14 @@ async fn handle_oauth(oauth_args: &OauthArgs) {
2020
let mut auth_builder = AuthenticationBuilder::builder();
2121
auth_builder
2222
.of_type(AuthType::Oauth)
23-
.client_id(&oauth_args.client_id)
24-
.client_secret(&oauth_args.client_secret)
23+
.client_id(Some(&oauth_args.client_id))
24+
.client_secret(Some(&oauth_args.client_secret))
2525
.bedrockrel(oauth_args.bedrockrelm)
2626
.port(oauth_args.port);
2727

2828
println!("{:?}", auth_builder.get_info().await);
2929

30-
let auth_info = auth_builder.launch().await.unwrap();
30+
let auth_info = auth_builder.launch(None, None).await.unwrap();
3131

3232
println!("{:?}", auth_info)
3333
}
@@ -36,12 +36,12 @@ async fn handle_device_code(device_code_args: &DeviceCodeArgs) {
3636
let mut auth_builder = AuthenticationBuilder::builder();
3737
auth_builder
3838
.of_type(AuthType::DeviceCode)
39-
.client_id(&device_code_args.client_id)
39+
.client_id(Some(&device_code_args.client_id))
4040
.bedrockrel(Some(device_code_args.bedrockrelm));
4141

4242
println!("{:?}", auth_builder.get_info().await);
4343

44-
println!("{:?}", auth_builder.launch().await);
44+
println!("{:?}", auth_builder.launch(None, None).await);
4545
}
4646

4747
// async fn handle_launch(arg: &LaucnhArgs) {

0 commit comments

Comments
 (0)