use crate::consts;
use crate::error::AuthResult;
use serde::Deserialize;
use serde_json::json;
use time::{Duration, OffsetDateTime};
#[derive(Clone, Debug)]
pub struct MinecraftToken {
pub username: String,
pub access_token: String,
pub expiration: OffsetDateTime,
}
#[instrument(name = "authenticate_minecraft", level = "trace", skip_all)]
pub async fn authenticate(xsts_token: &str, user_hash: &str) -> AuthResult<MinecraftToken> {
let client = reqwest::Client::new();
let response = client
.post(consts::MC_TOKEN_URL)
.json(&json!({
"identityToken": format!("XBL3.0 x={};{}", user_hash, xsts_token)
}))
.send()
.await?
.error_for_status()?
.json::<MinecraftTokenResponse>()
.await?;
Ok(response.into())
}
#[derive(Clone, Debug, Deserialize)]
struct MinecraftTokenResponse {
username: String,
access_token: String,
expires_in: u64,
}
impl From<MinecraftTokenResponse> for MinecraftToken {
fn from(resp: MinecraftTokenResponse) -> Self {
let exp = OffsetDateTime::now_utc() - Duration::seconds(60)
+ Duration::seconds(resp.expires_in as i64);
Self {
username: resp.username,
access_token: resp.access_token,
expiration: exp,
}
}
}