minecraft-essentials 0.2.11

A Package that gives all Minecraft client launchers essentials.
Documentation
#![forbid(unsafe_code, missing_docs)]
#![warn(clippy::pedantic)]

use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::error::Error;

use crate::async_trait_alias::AsyncSendSync;

/// Defines the custom authentication data received from Mojang.
///
/// This struct contains the necessary information for authenticating a user with Mojang's services,
/// including the access token for API requests, the user's UUID, the token's expiry time, and an optional
/// XTS token for Bedrock Realms.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct AuthInfo {
    /// The bearer token received from Mojang.
    ///
    /// This token is used for making authenticated requests to Mojang's APIs, such as launching the game
    /// or accessing user-specific data. It is crucial for the authentication process and should be
    /// securely stored and used.
    pub access_token: String,

    /// The UUID of the authenticated user.
    ///
    /// This UUID is not the player's Minecraft UUID but a unique identifier generated by Mojang for
    /// authentication purposes. It is used for launching the game and should be treated as sensitive
    /// information.
    pub uuid: String,

    /// The expiry time of the access token in seconds.
    ///
    /// This field indicates how long the access token is valid. After this time, the token will expire,
    /// and a new one must be obtained to continue making authenticated requests.
    pub expires_in: i32,

    /// The XTS token for Bedrock Realms.
    ///
    /// If the user is authenticating for Bedrock Realms, this field will contain the XTS token. This token
    /// is used specifically for accessing Bedrock Realms features and is only present if the user is
    /// authenticating for Bedrock Realms.
    pub xts_token: Option<String>,
}

#[derive(Debug, Deserialize)]
struct MojangResponse {
    username: String,
    access_token: String,
    token_type: String,
    expires_in: i32,
}

pub fn token(
    userhash: &str,
    xsts_token: &str,
) -> impl AsyncSendSync<Result<AuthInfo, Box<dyn Error>>> {
    let client = Client::new();
    let identity_token = format!("XBL3.0 x={};{}", userhash, xsts_token);
    let body = json!({
        "identityToken": identity_token
    });
    tokeninternal(client, body)
}

async fn tokeninternal(client: Client, body: Value) -> Result<AuthInfo, Box<dyn Error>> {
    let res = client
        .post("https://api.minecraftservices.com/authentication/login_with_xbox")
        .body(body.to_string())
        .send()
        .await?;

    let response: MojangResponse = res.json().await?;

    if response.token_type != "Bearer" {
        println!("Sorry, we ran into an error in authentication.");
        return Err("Invalid token type".into());
    }
    let access_token = response.access_token;
    let uuid = response.username;
    let expires_in = response.expires_in; // Ensure this is correctly set to the expiration time

    Ok(AuthInfo {
        uuid: uuid,
        access_token: access_token,
        expires_in: expires_in, // This should correctly reflect the expiration time
        xts_token: None,        // Assuming this is handled elsewhere or not relevant for this issue
    })
}