XalAuthenticator

Struct XalAuthenticator 

Source
pub struct XalAuthenticator { /* private fields */ }
Expand description

XAL Authenticator

Implementations§

Source§

impl XalAuthenticator

Static methods

Source

pub fn generate_random_state() -> CsrfToken

Generate OAuth2 random state

Examples

let state = XalAuthenticator::generate_random_state();
Source

pub fn generate_code_verifier() -> (PkceCodeChallenge, PkceCodeVerifier)

Generate OAuth2 code verifier

§Examples
let (pkce_challenge, pkce_verifier) = XalAuthenticator::generate_code_verifier();
Source

pub fn get_device_code_verification_uri( user_code: &UserCode, ) -> VerificationUriComplete

Obtain an alternative URL for the device code verification process

This method generates a URL with the device code already prefilled. Users only need to visit this URL and authenticate their account without copying and pasting the code.

§Arguments
  • user_code - The user code generated during the device code flow initialization.
§Returns
  • VerificationUriComplete - A URL with the device code already prefilled.
§Examples
use xal::XalAuthenticator;
use xal::oauth2::UserCode;

let user_code = UserCode::new("abc123".to_string());
let verification_uri = XalAuthenticator::get_device_code_verification_uri(&user_code);
println!("{:?}", verification_uri);
Source

pub fn parse_authorization_code_response( redirect_url: &Url, expected_state: Option<&CsrfToken>, ) -> Result<AuthorizationCode, Error>

Parse OAuth2 authorization response by providing the full redirect url containing a code= query parameter

§Arguments
  • redirect_url - The full url of the redirect endpoint containing the code= query parameter.
  • expected_state - (Optional) The expected state that should match the state returned by the server. If the states do not match, an error will be returned.
§Returns
  • Ok(AuthorizationCode) - On successful validation of the server response and retrieval of the authorization code.
  • Err(Error) - If there is an error while parsing the server response or if the states do not match.
§Errors
  • Error::GeneralError - If there is a problem with the response url.
  • Error::OAuthExecutionError - If there is an error with the server response or if the authorization code is not present.
§Examples
use xal::{
    XalAuthenticator, url::Url,
    oauth2::CsrfToken,
};
let url = Url::parse("https://example.com/?code=123&state=ABC").unwrap();
let code = XalAuthenticator::parse_authorization_code_response(
    &url,
    Some(&CsrfToken::new("ABC".into())),
).unwrap();

assert_eq!(code.secret(), "123");
Source

pub fn parse_implicit_grant_url( url: &Url, expected_state: Option<&CsrfToken>, ) -> Result<WindowsLiveTokens, Error>

Parse OAuth2 implicit grant response

This method takes a URL with an OAuth2 implicit grant response and optionally a CSRF token. It parses the response, verifies the CSRF token if provided, and returns the access token.

§Arguments
  • url - The URL containing the OAuth2 implicit grant response.
  • expected_state - Optionally, a CSRF token to verify against.
§Returns
  • Result<response::WindowsLiveTokens, Error> - The access token and token type.
§Examples
use xal::XalAuthenticator;
use xal::oauth2::{CsrfToken, TokenResponse};
use xal::url::Url;

let url = Url::parse(
    "https://example.com/callback#access_token=token123&token_type=Bearer&expires_in=3600&state=123abc"
)
.unwrap();

let live_tokens = XalAuthenticator::parse_implicit_grant_url(
    &url,
    Some(&CsrfToken::new("123abc".into()))
).unwrap();

assert_eq!(live_tokens.access_token().secret(), "token123");
Source§

impl XalAuthenticator

OAuth2 request functionality

Source

pub fn new( app_params: XalAppParameters, client_params: XalClientParameters, sandbox_id: String, ) -> Self

Create a new instance of the XAL Authenticator

This method initializes an instance of the XAL Authenticator with the specified app_params, client_params, and sandbox_id.

See constants in crate::models::app_params for crate::XalAppParameters and crate::models::client_params for crate::XalClientParameters.

§Examples

Instantiate explicitly with app/client parameters

use xal::{XalAuthenticator, app_params, client_params};
let authenticator = XalAuthenticator::new(
    app_params::APP_GAMEPASS_BETA(),
    client_params::CLIENT_ANDROID(),
    "RETAIL".into(),
);
§Notes

If you don’t have specific needs for client parameters, use crate::XalAuthenticator::default

Source

pub fn with_device_id( app_params: XalAppParameters, client_params: XalClientParameters, sandbox_id: String, device_id: Uuid, ) -> Self

Create a new instance of the XAL Authenticator with explicit Device Id.

See new() method.

§Examples

Instantiate explicitly with app/client parameters and device id

use xal::{XalAuthenticator, app_params, client_params};
let authenticator = XalAuthenticator::with_device_id(
    app_params::APP_GAMEPASS_BETA(),
    client_params::CLIENT_ANDROID(),
    "RETAIL".into(),
    uuid::uuid!("dc1183d0-a9f8-4c3f-a2a9-83706023791e")
);
§Notes

If you don’t have specific needs for client parameters, use crate::XalAuthenticator::default

Source

pub fn device_id(&self) -> Uuid

Get Device Id

Source

pub fn sandbox_id(&self) -> String

Get configured sandbox id

Source

pub fn app_params(&self) -> XalAppParameters

Get active app parameters

Source

pub fn client_params(&self) -> XalClientParameters

Get active client parameters

Source

pub fn request_signer(&self) -> RequestSigner

Get request signer instance

Source

pub fn get_redirect_uri(&self) -> Option<Url>

Get redirection Url

Source

pub fn oauth_client(&self) -> Result<BasicClient, Error>

Create an internal oauth2::Client

Refer to oauth2 crate for it’s usage

Source

pub fn get_authorization_url( &mut self, implicit_flow: bool, ) -> Result<(EndUserVerificationUrl, CsrfToken), Error>

Gets the authorization URL for the OAuth2 authentication flow.

When the user clicks the link in the URL, they will be prompted to sign in with their Xbox Live account.

Defining a redirect_url in crate::XalAppParameters is mandatory for this authentication flow

§Examples
use xal::{XalAuthenticator, XalAppParameters, client_params};
use xal::oauth2::{RedirectUrl, Scope};

let mut authenticator = XalAuthenticator::new(
    XalAppParameters {
        client_id: "388ea51c-0b25-4029-aae2-17df49d23905".into(),
        title_id: None,
        auth_scopes: vec![
            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()),
        client_secret: None,
    },
    client_params::CLIENT_ANDROID(),
    "RETAIL".into()
);

let (url, state) = authenticator.get_authorization_url(false)
    .unwrap();

assert!(url.as_str().starts_with("https://login.live.com/oauth20_desktop.srf"));
Source

pub async fn initiate_device_code_auth( &mut self, ) -> Result<StandardDeviceAuthorizationResponse, Error>

Initiates the Device Code Authentication Flow.

After presenting the returned [crate::oauth2:: EndUserVerificationUrl] and crate::oauth2::UserCode to the user, call poll_device_code_auth.

You can transform the returned value into crate::oauth2::VerificationUriComplete by calling get_device_code_verification_uri.

§Examples
use xal::XalAuthenticator;

let mut authenticator = XalAuthenticator::default();
let device_code_resp = authenticator
    .initiate_device_code_auth()
    .await
    .unwrap();
// Present authentication parameters from `device_code_resp` to user
let live_tokens = authenticator
    .poll_device_code_auth(&device_code_resp, tokio::time::sleep)
    .await
    .unwrap();

println!("{live_tokens:?}");
Source

pub async fn poll_device_code_auth<S, SF>( &mut self, device_auth_resp: &StandardDeviceAuthorizationResponse, sleep_fn: S, ) -> Result<WindowsLiveTokens, Error>
where S: Fn(Duration) -> SF, SF: Future<Output = ()>,

Poll for device code.

To be called after presenting the result of start_device_code_auth to the user.

§Arguments
  • sleep_fn is the impl of an async sleep function
§Examples
use xal::XalAuthenticator;

let mut authenticator = XalAuthenticator::default();
let device_code_resp = authenticator
    .initiate_device_code_auth()
    .await
    .unwrap();
// Present authentication parameters from `device_code_resp` to user
let live_tokens = authenticator
    .poll_device_code_auth(&device_code_resp, tokio::time::sleep)
    .await
    .unwrap();

println!("{live_tokens:?}");
Source

pub async fn exchange_code_for_token( &mut self, authorization_code: AuthorizationCode, code_verifier: Option<PkceCodeVerifier>, ) -> Result<WindowsLiveTokens, Error>

Exchange OAuth2 Authorization Token for Windows Live Access Token.

This method utilizes the PKCE extension to securely obtain an access token from the Microsoft Identity Platform.

§Arguments
  • authorization_code - The authorization code received from the user authentication step.
  • code_verifier - The code verifier that was generated earlier in the PKCE process. This parameter is optional.
§Examples
use xal::XalAuthenticator;
use xal::oauth2::{AuthorizationCode, TokenResponse};
let mut authenticator = XalAuthenticator::default();
let code = AuthorizationCode::new("123".to_string());
let live_tokens = authenticator
    .exchange_code_for_token(code, None)
    .await?;

assert!(!live_tokens.access_token().secret().is_empty());
Source

pub async fn refresh_token_for_scope<T>( &mut self, refresh_token: &RefreshToken, scopes: Vec<Scope>, ) -> Result<T, Error>

Refresh an OAuth2 Refresh Token for specific scope(s) and deserialize into custom response type

This is used when the token response does not align with the standard.

§Examples
use xal::XalAuthenticator;
use xal::oauth2::{RefreshToken, Scope};
use serde::{Deserialize, Serialize};

// Custom JSON response body
#[derive(Debug, Serialize, Deserialize)]
pub struct XCloudTokenResponse {
    pub lpt: String,
    pub refresh_token: String,
    pub user_id: String,
}

let mut authenticator = XalAuthenticator::default();
let scopes = vec![
    Scope::new(
        "service::http://Passport.NET/purpose::PURPOSE_XBOX_CLOUD_CONSOLE_TRANSFER_TOKEN".into()
    )
];

let token_response = authenticator
    .refresh_token_for_scope::<XCloudTokenResponse>(
        &refresh_token,
        scopes
    )
    .await
    .unwrap();
Source

pub async fn refresh_token( &mut self, refresh_token: &RefreshToken, ) -> Result<WindowsLiveTokens, Error>

Refresh a Windows Live Refresh & Access Token by providing a Refresh Token

§Arguments
  • refresh_token - The refresh token to use for obtaining a new access token
§Examples
use xal::XalAuthenticator;
use xal::oauth2::RefreshToken;

let mut authenticator = XalAuthenticator::default();
let refresh_token = RefreshToken::new("old_refresh_token".to_string());
let refreshed_live_tokens = authenticator
    .refresh_token(&refresh_token)
    .await
    .unwrap();

println!("Refreshed tokens: {refreshed_live_tokens:?}");
Source§

impl XalAuthenticator

Xbox Live token functionality

Source

pub async fn sisu_authenticate( &mut self, device_token: &DeviceToken, code_challenge: &PkceCodeChallenge, state: &CsrfToken, ) -> Result<(SisuAuthenticationResponse, SisuSessionId), Error>

Initiate authentication via SISU flow

§Parameters
§Errors
  • If device_token is missing.
  • If redirect_uri is missing.
  • If the Sisu Authentication request fails.
§Examples
use xal::XalAuthenticator;
use xal::url::Url;

let mut authenticator = XalAuthenticator::default();
let state = XalAuthenticator::generate_random_state();
let (pkce_challenge, pkce_verifier) = XalAuthenticator::generate_code_verifier();
let device_token = authenticator.get_device_token()
    .await
    .unwrap();

let (resp, session_id) = authenticator.sisu_authenticate(
    &device_token,
    &pkce_challenge,
    &state
)
.await
.unwrap();

println!(
    "Visit this url and pass back the redirect url containing the authorization code {}",
    resp.msa_oauth_redirect
);
let redirect_url = Url::parse("https://example.com/?code=123").unwrap();

let authorization_code = XalAuthenticator::parse_authorization_code_response(
    &redirect_url, Some(&state)
).unwrap();

let live_tokens = authenticator.exchange_code_for_token(
    authorization_code, Some(pkce_verifier)
)
.await
.unwrap();

let sisu_authorization_resp = authenticator.sisu_authorize(
    &live_tokens, &device_token, Some(session_id)
)
.await
.unwrap();
§Notes

It is mandatory to have XalAppParameters setup with a redirect_uri and title_id.

Source

pub async fn sisu_authorize( &mut self, access_token: &WindowsLiveTokens, device_token: &DeviceToken, sisu_session_id: Option<SisuSessionId>, ) -> Result<SisuAuthorizationResponse, Error>

Authorize via SISU flow after completing OAuth2 Authentication

This function handles the second step of the SISU flow. The response from the server contains a collection of tokens, which can be used for further interaction with the Xbox Live service.

§Examples
use xal::XalAuthenticator;
use xal::url::Url;

let mut authenticator = XalAuthenticator::default();
let state = XalAuthenticator::generate_random_state();
let (pkce_challenge, pkce_verifier) = XalAuthenticator::generate_code_verifier();
let device_token = authenticator.get_device_token()
    .await
    .unwrap();

let (resp, session_id) = authenticator.sisu_authenticate(
    &device_token,
    &pkce_challenge,
    &state
)
.await
.unwrap();

println!(
    "Visit this url and pass back the redirect url containing the authorization code {}",
    resp.msa_oauth_redirect
);
let redirect_url = Url::parse("https://example.com/?code=123").unwrap();

let authorization_code = XalAuthenticator::parse_authorization_code_response(
    &redirect_url, Some(&state)
).unwrap();

let live_tokens = authenticator.exchange_code_for_token(
    authorization_code, Some(pkce_verifier)
)
.await
.unwrap();

let sisu_authorization_resp = authenticator.sisu_authorize(
    &live_tokens, &device_token, Some(session_id)
)
.await
.unwrap();
Source

pub async fn get_device_token(&mut self) -> Result<DeviceToken, Error>

Requests a Xbox Live Device Token from the Xbox Live authentication service.

This method is responsible for requesting a Xbox Live Device Token, which identifies a client device to the Xbox service.

§Errors

This method returns an Error if the POST request fails or the JSON response cannot be parsed.

§Examples
use xal::XalAuthenticator;

let mut authenticator = XalAuthenticator::default();
let device_token = authenticator.get_device_token()
    .await
    .unwrap();

assert!(!device_token.token.is_empty());
§Notes

Device tokens can only be requested for devices of the following type:

  • Android
  • iOS
  • Nintendo
  • Win32

Xbox devices use a much more sophisticated request method.

Source

pub async fn get_user_token( &mut self, access_token: &WindowsLiveTokens, prefix: AccessTokenPrefix, ) -> Result<UserToken, Error>

Retrieves a Xbox User Token for a specified Access Token.

This method sends a POST request to the Xbox Live User Authentication URL, using the provided access_token and prefix.

The resulting User Token is then used to retrieve the final XSTS token to access Xbox Live services.

§Arguments
  • access_token - The Windows Live access token.
  • prefix - The access token prefix, either “d=”, “t=” or None.
§Errors

This method returns an crate::Error if the POST request fails or the JSON response cannot be parsed.

§Examples
use xal::{XalAuthenticator, Flows, Error, AccessTokenPrefix, CliCallbackHandler};
use xal::response::WindowsLiveTokens;

let mut authenticator = XalAuthenticator::default();

let token_store = Flows::ms_device_code_flow(
    &mut authenticator,
    CliCallbackHandler,
    tokio::time::sleep
)
.await?;

let user_token = authenticator.get_user_token(
    &token_store.live_token,
    AccessTokenPrefix::D,
)
.await?;
Source

pub async fn get_title_token( &mut self, access_token: &WindowsLiveTokens, device_token: &DeviceToken, ) -> Result<TitleToken, Error>

Retrieves a Title Token for a specified Access Token and Device Token.

This method sends a POST request to the Xbox Live Title Authentication URL, using the provided access_token and device_token.

The resulting Title Token is then used to retrieve the final XSTS token to access Xbox Live services.

§Arguments
  • access_token - The Windows Live access token.
  • device_token - The Xbox Live device token.
§Errors

This method returns an Error if the POST request fails or the JSON response cannot be parsed.

§Examples
use xal::{XalAuthenticator, Flows, Error, AccessTokenPrefix, CliCallbackHandler};

let mut authenticator = XalAuthenticator::new(
    xal::app_params::MC_BEDROCK_SWITCH(),
    xal::client_params::CLIENT_NINTENDO(),
    "RETAIL".into()
);

let token_store = Flows::ms_device_code_flow(
    &mut authenticator,
    CliCallbackHandler,
    tokio::time::sleep
)
.await?;

let device_token = authenticator.get_device_token()
    .await?;
  
let title_token = authenticator.get_title_token(
    &token_store.live_token,
    &device_token,
)
.await?;
Source

pub async fn get_xsts_token( &mut self, device_token: Option<&DeviceToken>, title_token: Option<&TitleToken>, user_token: Option<&UserToken>, relying_party: &str, ) -> Result<XSTSToken, Error>

Authenticates with the Xbox Live service and retrieves an XSTS token.

This method sends a POST request to the Xbox Live XSTS Authentication URL, using the provided relying_party and optionally device_token, title_token, and user_token.

The resulting XSTS token can be used to authenticate with various Xbox Live services.

§Arguments
  • device_token - (Optional) The Xbox Live device token.
  • title_token - (Optional) The Xbox Live title token.
  • user_token - (Optional) The Xbox Live user token.
  • relying_party - The relying party of the application.
§Errors

This method returns an Error if the POST request fails or the JSON response cannot be parsed.

§Examples
use xal::{XalAuthenticator, Flows, Error, AccessTokenPrefix, CliCallbackHandler};
use xal::response::WindowsLiveTokens;

let mut authenticator = XalAuthenticator::new(
    xal::app_params::MC_BEDROCK_SWITCH(),
    xal::client_params::CLIENT_NINTENDO(),
    "RETAIL".into()
);

let token_store = Flows::ms_device_code_flow(
    &mut authenticator,
    CliCallbackHandler,
    tokio::time::sleep
)
.await?;

let device_token = authenticator.get_device_token()
    .await?;
  
let title_token = authenticator.get_title_token(
    &token_store.live_token,
    &device_token,
)
.await?;

let user_token = authenticator.get_user_token(
    &token_store.live_token,
    AccessTokenPrefix::None,
)
.await?;

let xsts_token = authenticator.get_xsts_token(
    Some(&device_token),
    Some(&title_token),
    Some(&user_token),
    "rp://api.minecraftservices.com/",
).await?;

Trait Implementations§

Source§

impl Debug for XalAuthenticator

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for XalAuthenticator

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl From<TokenStore> for XalAuthenticator

Source§

fn from(value: TokenStore) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,