Skip to content

Commit e56c3bc

Browse files
authored
Merge pull request #3 from OpenXbox/feat/halo_waypoint_auth
examples: Add Halo waypoint auth examples, add descriptions
2 parents 69232a3 + 66b3147 commit e56c3bc

File tree

7 files changed

+135
-9
lines changed

7 files changed

+135
-9
lines changed

examples/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ name = "auth_cli"
2929
[[bin]]
3030
name = "auth_azure"
3131

32+
[[bin]]
33+
name = "auth_minecraft"
34+
35+
[[bin]]
36+
name = "auth_halo"
37+
3238
[[bin]]
3339
name = "xbl_signed_request"
3440

examples/src/bin/auth_azure.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Authenticating via custom Azure Client Id to Xbox Live
2+
//!
13
use std::str::from_utf8;
24

35
use async_trait::async_trait;
@@ -56,6 +58,7 @@ impl AuthPromptCallback for HttpCallbackHandler {
5658

5759
#[tokio::main]
5860
async fn main() -> Result<(), Error> {
61+
eprintln!("NOTE: --flow authorization-code required!");
5962
auth_main(
6063
XalAppParameters {
6164
app_id: "388ea51c-0b25-4029-aae2-17df49d23905".into(),
@@ -76,8 +79,7 @@ async fn main() -> Result<(), Error> {
7679
redirect_url_base: "http://localhost:8080".into(),
7780
},
7881
)
79-
.await
80-
.ok();
82+
.await?;
8183

8284
Ok(())
8385
}

examples/src/bin/auth_cli.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1+
//! Authenticating by following instructions on the CLI
12
use xal::{AccessTokenPrefix, CliCallbackHandler, Error};
23
use xal_examples::auth_main_default;
34

45
#[tokio::main]
56
async fn main() -> Result<(), Error> {
6-
auth_main_default(AccessTokenPrefix::None, CliCallbackHandler)
7-
.await
8-
.ok();
7+
auth_main_default(AccessTokenPrefix::None, CliCallbackHandler).await?;
98

109
Ok(())
1110
}

examples/src/bin/auth_halo.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//! Halo Waypoint authentication
2+
//! - Acquiring Spartan token
3+
//! - Acquiring flighting Id
4+
//!
5+
//! Reference:
6+
//! Den Delimarsky, Halo Infinite Web API Authentication
7+
//! Blog post: https://den.dev/blog/halo-api-authentication/
8+
//!
9+
use chrono::{DateTime, Utc};
10+
use env_logger::Env;
11+
use serde::Deserialize;
12+
use serde_json::json;
13+
use xal::{extensions::JsonExDeserializeMiddleware, Error, TokenStore, XalAuthenticator};
14+
15+
#[derive(Debug, Deserialize)]
16+
pub struct SpartanTokenExpiry {
17+
#[serde(rename = "ISO8601Date")]
18+
pub iso8601_date: DateTime<Utc>,
19+
}
20+
21+
#[derive(Debug, Deserialize)]
22+
#[serde(rename_all = "PascalCase")]
23+
pub struct SpartanTokenResponse {
24+
pub expires_utc: SpartanTokenExpiry,
25+
pub spartan_token: String,
26+
pub token_duration: String,
27+
}
28+
29+
#[derive(Debug, Deserialize)]
30+
#[serde(rename_all = "PascalCase")]
31+
pub struct FlightConfiguration {
32+
pub flight_configuration_id: String,
33+
}
34+
35+
#[tokio::main]
36+
async fn main() -> Result<(), Error> {
37+
env_logger::Builder::from_env(Env::default().default_filter_or("trace")).init();
38+
39+
// Load tokens from JSON
40+
let token_store = TokenStore::load_from_file("tokens.json")?;
41+
42+
token_store
43+
.user_token
44+
.clone()
45+
.ok_or(Error::GeneralError("No User token available".into()))?;
46+
let xuid = token_store
47+
.authorization_token
48+
.clone()
49+
.ok_or(Error::GeneralError("No XSTS token available".into()))?
50+
.display_claims
51+
.ok_or(Error::GeneralError("No DisplayClaims".into()))?
52+
.xui
53+
.first()
54+
.ok_or(Error::GeneralError("No xui node".into()))?
55+
.get("xid")
56+
.ok_or(Error::GeneralError("No X(U)ID".into()))?
57+
.to_owned();
58+
59+
let mut authenticator = XalAuthenticator::from(token_store.clone());
60+
let xsts_halo_waypoint = authenticator
61+
.get_xsts_token(
62+
None,
63+
None,
64+
token_store.user_token.as_ref(),
65+
"https://prod.xsts.halowaypoint.com/",
66+
)
67+
.await?;
68+
69+
let xsts_token = xsts_halo_waypoint.token;
70+
71+
let spartan_token_request = json!({
72+
"Audience": "urn:343:s3:services",
73+
"MinVersion": "4",
74+
"Proof": [{
75+
"Token": xsts_token,
76+
"TokenType": "Xbox_XSTSv3"
77+
}]
78+
});
79+
80+
/* Halo stuff */
81+
let client = reqwest::ClientBuilder::new().build()?;
82+
83+
// Fetch spartan token
84+
let spartan_token = client
85+
.post("https://settings.svc.halowaypoint.com/spartan-token")
86+
.header(
87+
"User-Agent",
88+
"HaloWaypoint/2021112313511900 CFNetwork/1327.0.4 Darwin/21.2.0",
89+
)
90+
.header("Accept", "application/json")
91+
.json(&spartan_token_request)
92+
.send()
93+
.await?
94+
.json_ex::<SpartanTokenResponse>()
95+
.await?;
96+
println!("Spartan Token: {spartan_token:?}");
97+
98+
let clearance_url = format!("https://settings.svc.halowaypoint.com/oban/flight-configurations/titles/hi/audiences/RETAIL/players/xuid({xuid})/active?sandbox=UNUSED&build=210921.22.01.10.1706-0");
99+
// Get halo clearance token
100+
let flighting_config = client
101+
.get(clearance_url)
102+
.header(
103+
"User-Agent",
104+
"HaloWaypoint/2021112313511900 CFNetwork/1327.0.4 Darwin/21.2.0",
105+
)
106+
.header("Accept", "application/json")
107+
.header("x-343-authorization-spartan", spartan_token.spartan_token)
108+
.send()
109+
.await?
110+
.json_ex::<FlightConfiguration>()
111+
.await?;
112+
println!("Flighting: {flighting_config:?}");
113+
114+
Ok(())
115+
}

examples/src/bin/auth_minecraft.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Authenticating to Minecraft Bedrock as Nintendo-Switch-client
2+
//!
13
use serde_json::json;
24
use xal::{
35
extensions::JsonExDeserializeMiddleware, oauth2::TokenResponse, AccessTokenPrefix,

examples/src/bin/auth_webview.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,7 @@ async fn main() -> Result<(), Error> {
109109
.to_owned(),
110110
};
111111

112-
auth_main_default(AccessTokenPrefix::None, callback_handler)
113-
.await
114-
.ok();
112+
auth_main_default(AccessTokenPrefix::None, callback_handler).await?;
115113

116114
Ok(())
117115
}

examples/src/bin/xbl_signed_request.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Sending a signed http request to XBL userpresence API
2+
//!
13
use env_logger::Env;
24
use xal::{
35
cvlib::CorrelationVector,
@@ -39,8 +41,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3941
.send()
4042
.await?
4143
.log()
44+
.await?
45+
.text()
4246
.await?;
4347

44-
println!("{:?}", userpresence);
48+
println!("{userpresence}");
4549
Ok(())
4650
}

0 commit comments

Comments
 (0)