feat(auth): Update Google OAuth flow to support custom redirect URIs

This commit is contained in:
MythEclipse
2025-08-12 22:06:26 +07:00
parent 39fc2f86ad
commit 3cc3e2a7d8
2 changed files with 24 additions and 12 deletions
@@ -19,6 +19,11 @@ pub struct GoogleAuthUrlResponse {
pub authorize_url: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct GoogleLoginRequest {
pub redirect_uri: Option<String>,
}
pub struct GoogleOauthController<T> {
google_oauth_service: T,
}
@@ -49,8 +54,8 @@ where
.route(
"/login",
get(
move |State(controller): State<Arc<Self>>| async move {
controller.google_oauth_login().await
move |State(controller): State<Arc<Self>>, Query(params): Query<GoogleLoginRequest>| async move {
controller.google_oauth_login(params).await
},
),
)
@@ -66,8 +71,8 @@ where
.with_state(Arc::new(self.clone()))
}
pub async fn google_oauth_login(&self) -> Result<Redirect, Error> {
let (authorize_url, _csrf_state) = self.google_oauth_service.generate_auth_url();
pub async fn google_oauth_login(&self, params: GoogleLoginRequest) -> Result<Redirect, Error> {
let (authorize_url, _csrf_state) = self.google_oauth_service.generate_auth_url(params.redirect_uri);
Ok(Redirect::to(authorize_url.as_str()))
}
@@ -89,8 +89,8 @@ async fn get_default_role_id(_env: &Env) -> Result<String, Error> {
pub trait GoogleOauthService<A: AuthServiceTrait + Send + Sync + 'static, U: UsersServiceTrait + Send + Sync + 'static>: Send + Sync + 'static {
// Removed new() from trait
fn with_services(auth_service: A, users_service: U, env: &'static Env) -> Self;
fn google_oauth_client(&self) -> BasicClient;
fn generate_auth_url(&self) -> (Url, CsrfToken);
fn google_oauth_client(&self, custom_redirect_uri: Option<String>) -> BasicClient;
fn generate_auth_url(&self, custom_redirect_uri: Option<String>) -> (Url, CsrfToken);
async fn google_oauth_callback(&self, auth_request: AuthRequest, app_state: &AppState) -> Result<(UsersDetailItemDto, TokenDto), Error>; // Changed return type
}
@@ -103,7 +103,11 @@ pub struct GoogleOauthServiceImpl<A: AuthServiceTrait, U: UsersServiceTrait> {
}
impl GoogleOauthServiceImpl<crate::v1::auth::auth_service::AuthService, crate::v1::users::users_service::UsersService> {
// Removed the `new()` method as it will be replaced by `with_services`
/// Generate Google OAuth authorization URL
pub fn get_auth_url(&self, custom_redirect_uri: Option<String>) -> String {
let (auth_url, _csrf_token) = self.generate_auth_url(custom_redirect_uri);
auth_url.to_string()
}
}
#[async_trait]
@@ -120,7 +124,7 @@ where
}
}
fn google_oauth_client(&self) -> BasicClient {
fn google_oauth_client(&self, custom_redirect_uri: Option<String>) -> BasicClient {
let google_client_id = ClientId::new(self.env.google_client_id.clone());
let google_client_secret = ClientSecret::new(self.env.google_client_secret.clone());
let auth_url = AuthUrl::new("https://accounts.google.com/o/oauth2/v2/auth".to_string())
@@ -128,6 +132,8 @@ where
let token_url = TokenUrl::new("https://oauth2.googleapis.com/token".to_string())
.expect("Invalid token endpoint URL");
let redirect_uri = custom_redirect_uri.unwrap_or_else(|| self.env.google_redirect_url.clone());
BasicClient::new(
google_client_id,
Some(google_client_secret),
@@ -135,13 +141,13 @@ where
Some(token_url),
)
.set_redirect_uri(
RedirectUrl::new(self.env.google_redirect_url.clone())
RedirectUrl::new(redirect_uri)
.expect("Invalid redirect URL"),
)
}
fn generate_auth_url(&self) -> (Url, CsrfToken) {
let client = self.google_oauth_client();
fn generate_auth_url(&self, custom_redirect_uri: Option<String>) -> (Url, CsrfToken) {
let client = self.google_oauth_client(custom_redirect_uri);
let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256();
// Generate a signed CSRF token with PKCE verifier for stateless validation
@@ -167,7 +173,8 @@ where
info!("Starting Google OAuth callback process");
let client = self.google_oauth_client();
// Use the default client for the callback
let client = self.google_oauth_client(None);
let token_response = client
.exchange_code(oauth2::AuthorizationCode::new(auth_request.code))