pub(crate) mod http; use std::ops::Deref; use oauth2::{ AuthUrl, ClientId, ClientSecret, CsrfToken, EndpointNotSet, EndpointSet, RedirectUrl, Scope, TokenUrl, }; use secrecy::{ExposeSecret, SecretString}; use tracing::debug; use url::Url; use crate::{AuthServiceError, Provider}; type Inner = oauth2::basic::BasicClient< EndpointSet, EndpointNotSet, EndpointNotSet, EndpointNotSet, EndpointSet, >; #[derive(Debug, Clone)] pub struct OauthClient(Inner); impl Deref for OauthClient { type Target = Inner; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Debug, Clone)] pub struct ClientConfig { client_id: String, client_secret: SecretString, token_url: Url, auth_url: Url, } impl ClientConfig { pub fn new( client_id: String, client_secret: SecretString, token_url: Url, auth_url: Url, ) -> Self { Self { client_id, client_secret, token_url, auth_url, } } } impl TryFrom<&ClientConfig> for OauthClient { type Error = AuthServiceError; fn try_from(value: &ClientConfig) -> Result { debug!("creating oauth client"); Ok(Self( oauth2::basic::BasicClient::new(ClientId::new(value.client_id.to_string())) .set_client_secret(ClientSecret::new( value.client_secret.expose_secret().to_string(), )) .set_auth_uri(AuthUrl::from_url(value.auth_url.to_owned())) .set_token_uri(TokenUrl::from_url(value.token_url.to_owned())), )) } } impl OauthClient { #[must_use] pub fn with_redirect_url(self, url: &Url) -> Self { Self( self.0 .set_redirect_uri(RedirectUrl::from_url(url.to_owned())), ) } pub fn url_token(&self, provider: Provider) -> (Url, CsrfToken) { let req = self.0.authorize_url(CsrfToken::new_random); match provider { Provider::Discord => req.add_scope(Scope::new("identify".to_string())), } .url() } }