From a98c9fdf3507c8d9b1a4637ad5d8d3ec9d54b9bd Mon Sep 17 00:00:00 2001 From: tuxuser <462620+tuxuser@users.noreply.github.com> Date: Thu, 21 Dec 2023 23:55:56 +0100 Subject: [PATCH 1/3] app_params: Implement defining client_secret in XalAppParameters --- examples/src/bin/auth_azure.rs | 12 ++++++++---- src/authenticator.rs | 20 ++++++++++++-------- src/models.rs | 12 ++++++++++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/examples/src/bin/auth_azure.rs b/examples/src/bin/auth_azure.rs index 824bd2b..bf58620 100644 --- a/examples/src/bin/auth_azure.rs +++ b/examples/src/bin/auth_azure.rs @@ -15,6 +15,11 @@ use xal::{ }; use xal_examples::auth_main; +// Replace with your own Azure Client parameters +const CLIENT_ID: &'static str = "388ea51c-0b25-4029-aae2-17df49d23905"; +const REDIRECT_URL: &'static str = "http://localhost:8080/auth/callback"; +const CLIENT_SECRET: Option<&'static str> = None; + pub struct HttpCallbackHandler { bind_host: String, redirect_url_base: String, @@ -61,15 +66,14 @@ async fn main() -> Result<(), Error> { eprintln!("NOTE: --flow authorization-code required!"); auth_main( XalAppParameters { - app_id: "388ea51c-0b25-4029-aae2-17df49d23905".into(), + app_id: CLIENT_ID.into(), title_id: None, auth_scopes: vec![ Scope::new("Xboxlive.signin".into()), Scope::new("Xboxlive.offline_access".into()), ], - redirect_uri: Some( - RedirectUrl::new("http://localhost:8080/auth/callback".into()).unwrap(), - ), + redirect_uri: Some(RedirectUrl::new(REDIRECT_URL.into()).unwrap()), + client_secret: CLIENT_SECRET.map(|x| x.to_string()), }, CLIENT_ANDROID(), "RETAIL".into(), diff --git a/src/authenticator.rs b/src/authenticator.rs index 2c5d0c7..84f6ac5 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -407,10 +407,13 @@ impl XalAuthenticator { /// Create an internal [`oauth2::Client`] /// /// Refer to [`oauth2`] crate for it's usage - pub fn oauth_client(&self, client_secret: Option) -> Result { + pub fn oauth_client(&self) -> Result { let client = OAuthClient::new( ClientId::new(self.app_params.app_id.to_string()), - client_secret, + self.app_params + .client_secret + .clone() + .map(|x| ClientSecret::new(x)), AuthUrl::new(Constants::OAUTH20_AUTHORIZE_URL.to_string())?, Some(TokenUrl::new(Constants::OAUTH20_TOKEN_URL.to_string())?), ) @@ -444,7 +447,8 @@ impl XalAuthenticator { /// Scope::new("Xboxlive.signin".into()), /// Scope::new("Xboxlive.offline_access".into()) /// ], - /// redirect_uri: Some(RedirectUrl::new("https://login.live.com/oauth20_desktop.srf".into()).unwrap()) + /// redirect_uri: Some(RedirectUrl::new("https://login.live.com/oauth20_desktop.srf".into()).unwrap()), + /// client_secret: None, /// }, /// client_params::CLIENT_ANDROID(), /// "RETAIL".into() @@ -461,7 +465,7 @@ impl XalAuthenticator { implicit_flow: bool, ) -> Result<(EndUserVerificationUrl, CsrfToken), Error> { let client = - self.oauth_client(None)? + self.oauth_client()? .set_redirect_uri(self.app_params.redirect_uri.clone().ok_or( Error::InvalidRedirectUrl("Redirect URL was not provided".into()), )?); @@ -508,7 +512,7 @@ impl XalAuthenticator { pub async fn initiate_device_code_auth( &mut self, ) -> Result { - self.oauth_client(None)? + self.oauth_client()? .exchange_device_code() .unwrap() .add_scopes(self.app_params.auth_scopes.clone()) @@ -555,7 +559,7 @@ impl XalAuthenticator { S: Fn(std::time::Duration) -> SF, SF: std::future::Future, { - self.oauth_client(None)? + self.oauth_client()? .exchange_device_access_token(device_auth_resp) .request_async(&async_http_client, sleep_fn, None) .await @@ -592,7 +596,7 @@ impl XalAuthenticator { authorization_code: AuthorizationCode, code_verifier: Option, ) -> Result { - let client = self.oauth_client(None)?; + let client = self.oauth_client()?; let mut req = client.exchange_code(authorization_code); @@ -656,7 +660,7 @@ impl XalAuthenticator { T: serde::de::DeserializeOwned, { let resp = self - .oauth_client(None)? + .oauth_client()? .exchange_refresh_token(refresh_token) .add_scopes(scopes) .request_async(&async_http_client) diff --git a/src/models.rs b/src/models.rs index 62c0bd3..69a7cf8 100644 --- a/src/models.rs +++ b/src/models.rs @@ -514,6 +514,8 @@ pub struct XalAppParameters { pub auth_scopes: Vec, /// Redirect Uri (For OAuth2 code response) pub redirect_uri: Option, + /// OAuth2 Client Secret + pub client_secret: Option, } /// Application parameter constants @@ -551,6 +553,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -564,6 +567,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -577,6 +581,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -590,6 +595,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -604,6 +610,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -616,6 +623,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -628,6 +636,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -640,6 +649,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -652,6 +662,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } @@ -664,6 +675,7 @@ pub mod app_params { redirect_uri: Some( RedirectUrl::new(crate::Constants::OAUTH20_DESKTOP_REDIRECT_URL.into()).unwrap(), ), + client_secret: None, } } From f5b0ea4cebbae58f3cf5aa397c528234df66c69c Mon Sep 17 00:00:00 2001 From: tuxuser <462620+tuxuser@users.noreply.github.com> Date: Fri, 22 Dec 2023 00:00:28 +0100 Subject: [PATCH 2/3] app_params: Rename XalAppParameters.app_id to client_id --- examples/src/bin/auth_azure.rs | 2 +- src/authenticator.rs | 8 ++++---- src/models.rs | 26 +++++++++++++------------- src/tokenstore.rs | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/src/bin/auth_azure.rs b/examples/src/bin/auth_azure.rs index bf58620..fa73336 100644 --- a/examples/src/bin/auth_azure.rs +++ b/examples/src/bin/auth_azure.rs @@ -66,7 +66,7 @@ async fn main() -> Result<(), Error> { eprintln!("NOTE: --flow authorization-code required!"); auth_main( XalAppParameters { - app_id: CLIENT_ID.into(), + client_id: CLIENT_ID.into(), title_id: None, auth_scopes: vec![ Scope::new("Xboxlive.signin".into()), diff --git a/src/authenticator.rs b/src/authenticator.rs index 84f6ac5..cfbd625 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -409,7 +409,7 @@ impl XalAuthenticator { /// Refer to [`oauth2`] crate for it's usage pub fn oauth_client(&self) -> Result { let client = OAuthClient::new( - ClientId::new(self.app_params.app_id.to_string()), + ClientId::new(self.app_params.client_id.to_string()), self.app_params .client_secret .clone() @@ -441,7 +441,7 @@ impl XalAuthenticator { /// # async fn demo_code() { /// let mut authenticator = XalAuthenticator::new( /// XalAppParameters { - /// app_id: "388ea51c-0b25-4029-aae2-17df49d23905".into(), + /// client_id: "388ea51c-0b25-4029-aae2-17df49d23905".into(), /// title_id: None, /// auth_scopes: vec![ /// Scope::new("Xboxlive.signin".into()), @@ -795,7 +795,7 @@ impl XalAuthenticator { ))?; let json_body = request::SisuAuthenticationRequest { - app_id: &self.app_params.app_id, + app_id: &self.app_params.client_id, title_id: &title_id, redirect_uri: self.app_params.redirect_uri.as_deref().ok_or( Error::InvalidRedirectUrl("sisu_authenticate requires Redirect URL".to_string()), @@ -896,7 +896,7 @@ impl XalAuthenticator { ) -> Result { let json_body = request::SisuAuthorizationRequest { access_token: &format!("t={}", access_token.access_token().secret()), - app_id: &self.app_params.app_id, + app_id: &self.app_params.client_id, device_token: &device_token.token, sandbox: &self.sandbox_id.clone(), site_name: "user.auth.xboxlive.com", diff --git a/src/models.rs b/src/models.rs index 69a7cf8..ab611b7 100644 --- a/src/models.rs +++ b/src/models.rs @@ -507,7 +507,7 @@ impl ToString for DeviceType { #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct XalAppParameters { /// App Id (For authorization/permission scope) - pub app_id: String, + pub client_id: String, /// App Title-Id (For TitleToken) pub title_id: Option, /// Scopes @@ -546,7 +546,7 @@ pub mod app_params { /// Xbox Beta App pub fn APP_XBOX_BETA() -> XalAppParameters { XalAppParameters { - app_id: "000000004415494b".into(), + client_id: "000000004415494b".into(), title_id: Some("177887386".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], // Originally "ms-xal-000000004415494b://auth" @@ -560,7 +560,7 @@ pub mod app_params { /// Xbox App pub fn APP_XBOX() -> XalAppParameters { XalAppParameters { - app_id: "000000004c12ae6f".into(), + client_id: "000000004c12ae6f".into(), title_id: Some("328178078".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], // Originally "ms-xal-000000004c12ae6f://auth" @@ -574,7 +574,7 @@ pub mod app_params { /// Gamepass App pub fn APP_GAMEPASS() -> XalAppParameters { XalAppParameters { - app_id: "000000004c20a908".into(), + client_id: "000000004c20a908".into(), title_id: Some("1016898439".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], // Originally "ms-xal-000000004c20a908://auth" @@ -588,7 +588,7 @@ pub mod app_params { /// Gamepass Beta App pub fn APP_GAMEPASS_BETA() -> XalAppParameters { XalAppParameters { - app_id: "000000004c20a908".into(), + client_id: "000000004c20a908".into(), title_id: Some("1016898439".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], // Originally "ms-xal-public-beta-000000004c20a908://auth" @@ -604,7 +604,7 @@ pub mod app_params { /// Uses default `oauth20_desktop.srf` redirect uri pub fn APP_FAMILY_SETTINGS() -> XalAppParameters { XalAppParameters { - app_id: "00000000482C8F49".into(), + client_id: "00000000482C8F49".into(), title_id: Some("1618633878".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: Some( @@ -617,7 +617,7 @@ pub mod app_params { /// Old Xbox App (non-sisu-flow) pub fn APP_OLD_XBOX_APP() -> XalAppParameters { XalAppParameters { - app_id: "0000000048093EE3".into(), + client_id: "0000000048093EE3".into(), title_id: None, auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: Some( @@ -630,7 +630,7 @@ pub mod app_params { /// Minecraft for Windows (JAVA) pub fn MC_JAVA_WIN32() -> XalAppParameters { XalAppParameters { - app_id: "00000000402b5328".into(), + client_id: "00000000402b5328".into(), title_id: None, auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: Some( @@ -643,7 +643,7 @@ pub mod app_params { /// Minecraft Bedrock (Nintendo Switch) pub fn MC_BEDROCK_SWITCH() -> XalAppParameters { XalAppParameters { - app_id: "00000000441cc96b".into(), + client_id: "00000000441cc96b".into(), title_id: Some("2047319603".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: Some( @@ -656,7 +656,7 @@ pub mod app_params { /// Minecraft Bedrock (Android) pub fn MC_BEDROCK_ANDROID() -> XalAppParameters { XalAppParameters { - app_id: "0000000048183522".into(), + client_id: "0000000048183522".into(), title_id: Some("1739947436".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: Some( @@ -669,7 +669,7 @@ pub mod app_params { /// Minecraft Bedrock (iOS) pub fn MC_BEDROCK_IOS() -> XalAppParameters { XalAppParameters { - app_id: "000000004c17c01a".into(), + client_id: "000000004c17c01a".into(), title_id: Some("1810924247".into()), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: Some( @@ -682,14 +682,14 @@ pub mod app_params { /* /// Minecraft Bedrock (Win32)) pub const MC_BEDROCK_WIN32: XalAppParameters = XalAppParameters { - app_id: "".into(), + client_id: "".into(), title_id: "896928775".into(), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: None, }; pub const MC_BEDROCK_PLAYSTATION: XalAppParameters = XalAppParameters { - app_id: "".into(), + client_id: "".into(), title_id: "2044456598".into(), auth_scopes: vec![Scope::new(Constants::SCOPE_SERVICE_USER_AUTH.to_string())], redirect_uri: None, diff --git a/src/tokenstore.rs b/src/tokenstore.rs index 786de34..0f1de92 100644 --- a/src/tokenstore.rs +++ b/src/tokenstore.rs @@ -190,10 +190,10 @@ mod tests { #[test] fn read_from_string() { - let tokens_str = r#"{"app_params":{"app_id":"00000000441cc96b","title_id":"42","auth_scopes":["service::user.auth.xboxlive.com::MBI_SSL"],"redirect_uri":"https://login.live.com/oauth20_desktop.srf"},"client_params":{"user_agent":"XAL","device_type":"NINTENDO","client_version":"0.0.0","query_display":"touch"},"sandbox_id":"RETAIL","live_token":{"access_token":"accessTokenABC","token_type":"bearer","expires_in":86400,"refresh_token":"refreshTokenABC","scope":"service::user.auth.xboxlive.com::MBI_SSL"}}"#; + let tokens_str = r#"{"app_params":{"client_id":"00000000441cc96b","title_id":"42","auth_scopes":["service::user.auth.xboxlive.com::MBI_SSL"],"redirect_uri":"https://login.live.com/oauth20_desktop.srf"},"client_params":{"user_agent":"XAL","device_type":"NINTENDO","client_version":"0.0.0","query_display":"touch"},"sandbox_id":"RETAIL","live_token":{"access_token":"accessTokenABC","token_type":"bearer","expires_in":86400,"refresh_token":"refreshTokenABC","scope":"service::user.auth.xboxlive.com::MBI_SSL"}}"#; let ts = TokenStore::deserialize_from_string(tokens_str).unwrap(); - assert_eq!(ts.app_params.app_id, "00000000441cc96b"); + assert_eq!(ts.app_params.client_id, "00000000441cc96b"); assert_eq!(ts.app_params.title_id, Some("42".into())); assert_eq!( ts.app_params.auth_scopes.first().unwrap().as_str(), From b80861de9c58bef1c6596cdeac9f284dcb5481e0 Mon Sep 17 00:00:00 2001 From: tuxuser <462620+tuxuser@users.noreply.github.com> Date: Fri, 22 Dec 2023 00:04:48 +0100 Subject: [PATCH 3/3] clippy, small documentation fixup --- src/authenticator.rs | 5 +---- src/models.rs | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/authenticator.rs b/src/authenticator.rs index cfbd625..c5dabc8 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -410,10 +410,7 @@ impl XalAuthenticator { pub fn oauth_client(&self) -> Result { let client = OAuthClient::new( ClientId::new(self.app_params.client_id.to_string()), - self.app_params - .client_secret - .clone() - .map(|x| ClientSecret::new(x)), + self.app_params.client_secret.clone().map(ClientSecret::new), AuthUrl::new(Constants::OAUTH20_AUTHORIZE_URL.to_string())?, Some(TokenUrl::new(Constants::OAUTH20_TOKEN_URL.to_string())?), ) diff --git a/src/models.rs b/src/models.rs index ab611b7..abaeffc 100644 --- a/src/models.rs +++ b/src/models.rs @@ -506,9 +506,9 @@ impl ToString for DeviceType { /// Mandatory for XAL authentication flow #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct XalAppParameters { - /// App Id (For authorization/permission scope) + /// OAuth2 Client Id pub client_id: String, - /// App Title-Id (For TitleToken) + /// App Title-Id (Required for SISU auth flow, for TitleToken) pub title_id: Option, /// Scopes pub auth_scopes: Vec,