Skip to content

Commit

Permalink
Add auth mod
Browse files Browse the repository at this point in the history
  • Loading branch information
itsyaasir committed Nov 9, 2023
1 parent 1e127c4 commit fda263a
Showing 1 changed file with 115 additions and 0 deletions.
115 changes: 115 additions & 0 deletions src/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::{ApiEnvironment, ApiError, Mpesa, MpesaError, MpesaResult};
use cached::proc_macro::cached;

use serde::{Deserialize, Serialize};

/// Response returned from the authentication function
#[derive(Debug, Serialize, Deserialize)]
pub struct AuthenticationResponse {
/// Access token which is used as the Bearer-Auth-Token
pub access_token: String,
/// Expiry time in seconds
pub expiry_in: u64,
}

impl std::fmt::Display for AuthenticationResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"token :{} expires in: {}",
self.access_token, self.expiry_in
)
}
}

#[cached(
size = 1,
time = 3600,
key = "String",
result = true,
convert = r#"{ format!("{}", client.client_key()) }"#
)]
pub(crate) async fn auth(client: &Mpesa<impl ApiEnvironment>) -> MpesaResult<String> {
let url = format!(
"{}/oauth/v1/generate?grant_type=client_credentials",
client.environment.base_url()
);
let response = client
.http_client
.get(&url)
.basic_auth(client.client_key(), Some(&client.client_secret()))
.send()
.await?;

if response.status().is_success() {
let value = response.json::<AuthenticationResponse>().await?;
let access_token = value.access_token;

return Ok(access_token);
}

let error = response.json::<ApiError>().await?;
Err(MpesaError::AuthenticationError(error))
}

#[cfg(test)]
mod tests {
use wiremock::{Mock, MockServer};

use super::*;
use crate::Environment;

#[derive(Debug, Clone)]
pub struct TestEnvironment {
pub server_url: String,
}

impl TestEnvironment {
pub async fn new(server: &MockServer) -> Self {
TestEnvironment {
server_url: server.uri(),
}
}
}

impl ApiEnvironment for TestEnvironment {
fn base_url(&self) -> &str {
&self.server_url
}

fn get_certificate(&self) -> &str {
include_str!("../src/certificates/sandbox")
}
}

#[tokio::test]
async fn test_cached_auth() {
use crate::Mpesa;
use cached::Cached;

let server = MockServer::start().await;

let env = TestEnvironment::new(&server).await;

let client = Mpesa::new("test_api_key", "test_public_key", env);

Mock::given(wiremock::matchers::method("GET"))
.respond_with(wiremock::ResponseTemplate::new(200).set_body_json(
AuthenticationResponse {
access_token: "test_token".to_string(),
expiry_in: 3600,
},
))
.expect(1)
.mount(&server)
.await;

auth_prime_cache(&client).await.unwrap();

let mut cache = AUTH.lock().await;

assert!(cache.cache_get(&client.client_key().to_string()).is_some());
assert_eq!(cache.cache_hits().unwrap(), 1);
assert_eq!(cache.cache_capacity().unwrap(), 1);
}
}

0 comments on commit fda263a

Please sign in to comment.