use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
use base64::Engine;
use std::collections::HashMap;
use crate::primitives::{OpenIDConfig, OpenIDTokenResponse, OpenIDUserInfo};
use crate::Res;
impl OpenIDConfig {
#[tracing::instrument]
pub async fn load_from_url(url: &str) -> Res<Self> {
Ok(reqwest::get(url).await?.json().await?)
}
#[tracing::instrument(skip(self, client_id, state, redirect_uri))]
pub fn gen_authorization_url(
&self,
client_id: &str,
state: &str,
redirect_uri: &str,
) -> String {
let client_id = urlencoding::encode(client_id);
let state = urlencoding::encode(state);
let redirect_uri = urlencoding::encode(redirect_uri);
format!("{}?response_type=code&scope=openid%20profile%20email&client_id={client_id}&state={state}&redirect_uri={redirect_uri}", self.authorization_endpoint)
}
#[tracing::instrument(skip(self, client_id, client_secret, code, redirect_uri))]
pub async fn request_token(
&self,
client_id: &str,
client_secret: &str,
code: &str,
redirect_uri: &str,
) -> Res<(OpenIDTokenResponse, String)> {
let authorization = BASE64_STANDARD.encode(format!("{client_id}:{client_secret}"));
let mut params = HashMap::new();
params.insert("grant_type", "authorization_code");
params.insert("code", code);
params.insert("redirect_uri", redirect_uri);
let response = reqwest::Client::new()
.post(&self.token_endpoint)
.header("Authorization", format!("Basic {authorization}"))
.form(¶ms)
.send()
.await?
.text()
.await?;
Ok((serde_json::from_str(&response)?, response))
}
#[tracing::instrument(skip(self, token))]
pub async fn request_user_info(
&self,
token: &OpenIDTokenResponse,
) -> Res<(OpenIDUserInfo, String)> {
let response = reqwest::Client::new()
.get(self.userinfo_endpoint.as_ref().expect(
"This client only support information retrieval through userinfo endpoint!",
))
.header("Authorization", format!("Bearer {}", token.access_token))
.send()
.await?
.text()
.await?;
Ok((serde_json::from_str(&response)?, response))
}
}