use crate::oauth2_http_client::Oauth2HttpClient;
use azure_core::{
error::{ErrorKind, ResultExt},
HttpClient, Url,
};
use oauth2::{basic::BasicClient, Scope};
use oauth2::{ClientId, ClientSecret};
use std::sync::Arc;
pub fn start(
client_id: ClientId,
client_secret: Option<ClientSecret>,
tenant_id: &str,
redirect_url: Url,
scopes: &[&str],
) -> AuthorizationCodeFlow {
let auth_url = oauth2::AuthUrl::from_url(
Url::parse(&format!(
"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize"
))
.expect("Invalid authorization endpoint URL"),
);
let token_url = oauth2::TokenUrl::from_url(
Url::parse(&format!(
"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"
))
.expect("Invalid token endpoint URL"),
);
let client = BasicClient::new(client_id, client_secret, auth_url, Some(token_url))
.set_auth_type(oauth2::AuthType::RequestBody)
.set_redirect_uri(oauth2::RedirectUrl::from_url(redirect_url));
let (pkce_code_challenge, pkce_code_verifier) = oauth2::PkceCodeChallenge::new_random_sha256();
let scopes = scopes.iter().map(ToString::to_string).map(Scope::new);
let (authorize_url, csrf_state) = client
.authorize_url(oauth2::CsrfToken::new_random)
.add_scopes(scopes)
.set_pkce_challenge(pkce_code_challenge)
.url();
AuthorizationCodeFlow {
client,
authorize_url,
csrf_state,
pkce_code_verifier,
}
}
#[derive(Debug)]
pub struct AuthorizationCodeFlow {
pub client: BasicClient,
pub authorize_url: Url,
pub csrf_state: oauth2::CsrfToken,
pub pkce_code_verifier: oauth2::PkceCodeVerifier,
}
impl AuthorizationCodeFlow {
pub async fn exchange(
self,
http_client: Arc<dyn HttpClient>,
code: oauth2::AuthorizationCode,
) -> azure_core::Result<
oauth2::StandardTokenResponse<oauth2::EmptyExtraTokenFields, oauth2::basic::BasicTokenType>,
> {
let oauth_http_client = Oauth2HttpClient::new(http_client.clone());
self.client
.exchange_code(code)
.set_pkce_verifier(self.pkce_code_verifier)
.request_async(|request| oauth_http_client.request(request))
.await
.context(
ErrorKind::Credential,
"exchanging an authorization code for a token failed",
)
}
}