genius-core-client 0.4.0

Genius Core Client Library. Written in Rust and using PyO3 for Python bindings.
Documentation
use crate::types::error::{ErrorCode, HstpError};

#[allow(dead_code)]
#[derive(Debug)]
pub struct TokenResponse {
    pub access_token: String,
}

#[allow(dead_code)]
pub async fn retrieve_auth_token_client_credentials(
    client_id: String,
    client_secret: String,
    token_url: String,
    audience: Option<String>,
    scope: Option<String>,
) -> Result<TokenResponse, HstpError> {
    use base64::{
        alphabet,
        engine::{GeneralPurpose, GeneralPurposeConfig},
        Engine,
    };

    // Create the authorization header
    let encoded_client_id = urlencoding::encode(&client_id);
    let encoded_client_secret = urlencoding::encode(&client_secret);
    let header = format!("{}:{}", encoded_client_id, encoded_client_secret);
    let header_ascii_bytes = header.as_bytes();

    let encoded_header = GeneralPurpose::new(&alphabet::STANDARD, GeneralPurposeConfig::default())
        .encode(header_ascii_bytes);

    let mut headers = reqwest::header::HeaderMap::new();
    headers.insert(
        reqwest::header::AUTHORIZATION,
        reqwest::header::HeaderValue::from_str(&format!("Basic {}", encoded_header))
            .map_err(HstpError::from_error)?,
    );
    headers.insert(
        reqwest::header::CONTENT_TYPE,
        reqwest::header::HeaderValue::from_static("application/x-www-form-urlencoded"),
    );

    // Build the request body
    let body = "grant_type=client_credentials".to_string();
    let body = if let Some(audience) = &audience {
        format!("{}&audience={}", body, audience)
    } else {
        body
    };
    let body = if let Some(scope) = &scope {
        format!("{}&scope={}", body, scope)
    } else {
        body
    };

    // Send the request
    let client = reqwest::Client::new();
    let response = client
        .post(token_url.to_string())
        .headers(headers)
        .body(body)
        .send()
        .await
        .map_err(HstpError::from_error)?;

    // Check the HTTP status code before parsing the response
    if response.status().is_success() {
        let response_body = response.text().await.map_err(HstpError::from_error)?;
        let response_body: serde_json::Value = serde_json::from_str(&response_body)?;
        let access_token = response_body["access_token"].as_str().ok_or_else(|| {
            HstpError::new(
                ErrorCode::None,
                "Failed to retrieve access token".to_string(),
                "".into(),
            )
        })?;

        Ok(TokenResponse {
            access_token: access_token.to_string(),
        })
    } else {
        let status = response.status().to_string(); // Store status before moving response
        let error_body = response.text().await.unwrap_or_else(|_| "".to_string());
        Err(HstpError::new(
            ErrorCode::UnhandledError,
            format!("Error response from server: {}", error_body),
            status,
        ))
    }
}