use reqwest::Client;
use url::Url;
mod error;
mod helpers;
mod types;
pub use error::AuthError;
pub use types::Tokens;
use self::types::{ApiStatus, GenerateTokenRequest, GenerateTokenResponse, RefreshTokenRequest};
pub fn generate_url(client_id: &str, redirect_uri: &str, state: &str) -> Result<Url, AuthError> {
let mut url = Url::parse("https://api-t1.fyers.in/api/v3/generate-authcode")?;
url.query_pairs_mut()
.append_pair("client_id", client_id)
.append_pair("redirect_uri", redirect_uri)
.append_pair("state", state)
.append_pair("response_type", "code");
Ok(url)
}
pub async fn generate_tokens(
client_id: &str,
secret_key: &str,
url: &str,
) -> Result<Tokens, AuthError> {
let app_id_hash = helpers::compute_app_id_hash(client_id, secret_key);
let parsed_url = Url::parse(url)?;
let auth_code =
helpers::get_query_param(&parsed_url, "auth_code").ok_or(AuthError::MissingAuthCode)?;
let client = Client::new();
let response = client
.post("https://api-t1.fyers.in/api/v3/validate-authcode")
.json(&GenerateTokenRequest::new(&app_id_hash, &auth_code))
.send()
.await?;
let api_response = response.json::<GenerateTokenResponse>().await?;
match api_response.s {
ApiStatus::Error => Err(AuthError::Api {
code: api_response.code,
message: api_response.message,
}),
ApiStatus::Ok => {
let access_token = api_response.access_token.ok_or_else(|| AuthError::Api {
code: api_response.code,
message: "missing access_token in success response".into(),
})?;
let refresh_token = api_response.refresh_token.ok_or_else(|| AuthError::Api {
code: api_response.code,
message: "missing refresh_token in success response".into(),
})?;
Ok(Tokens {
access_token,
refresh_token,
})
}
}
}
pub async fn refresh_tokens(
client_id: &str,
secret_key: &str,
refresh_token: &str,
pin: &str,
) -> Result<Tokens, AuthError> {
let app_id_hash = helpers::compute_app_id_hash(client_id, secret_key);
let client = Client::new();
let response = client
.post("https://api-t1.fyers.in/api/v3/validate-refresh-token")
.json(&RefreshTokenRequest::new(&app_id_hash, refresh_token, pin))
.send()
.await?;
let api_response = response.json::<GenerateTokenResponse>().await?;
match api_response.s {
ApiStatus::Error => Err(AuthError::Api {
code: api_response.code,
message: api_response.message,
}),
ApiStatus::Ok => {
let access_token = api_response.access_token.ok_or_else(|| AuthError::Api {
code: api_response.code,
message: "missing access_token in refresh response".into(),
})?;
Ok(Tokens {
access_token,
refresh_token: api_response
.refresh_token
.unwrap_or_else(|| refresh_token.to_string()),
})
}
}
}