""" Routes for Google authentication. """ from fastapi import APIRouter, HTTPException, Request, Response, status, Depends from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse import logging import json from typing import Dict, Any, Optional from datetime import datetime, timedelta from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import Flow from google.auth.transport.requests import Request as GoogleRequest from modules.shared.configuration import APP_CONFIG from modules.interfaces.serviceAppClass import getInterface, getRootInterface from modules.interfaces.serviceAppModel import AuthAuthority, User from modules.interfaces.serviceAppTokens import GoogleToken from modules.security.auth import getCurrentUser, limiter # Configure logger logger = logging.getLogger(__name__) # Create router router = APIRouter( prefix="/api/google", tags=["Security Google"], responses={ 404: {"description": "Not found"}, 400: {"description": "Bad request"}, 401: {"description": "Unauthorized"}, 403: {"description": "Forbidden"}, 500: {"description": "Internal server error"} } ) # Google OAuth configuration CLIENT_ID = APP_CONFIG.get("Service_GOOGLE_CLIENT_ID") CLIENT_SECRET = APP_CONFIG.get("Service_GOOGLE_CLIENT_SECRET") REDIRECT_URI = APP_CONFIG.get("Service_GOOGLE_REDIRECT_URI") SCOPES = [ "https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email" ] @router.get("/login") @limiter.limit("5/minute") async def login(request: Request) -> RedirectResponse: """Initiate Google login""" try: # Create OAuth flow flow = Flow.from_client_config( { "web": { "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "redirect_uris": [REDIRECT_URI] } }, scopes=SCOPES ) # Generate auth URL auth_url, _ = flow.authorization_url( access_type="offline", include_granted_scopes="true" ) return RedirectResponse(auth_url) except Exception as e: logger.error(f"Error initiating Google login: {str(e)}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to initiate Google login: {str(e)}" ) @router.get("/auth/callback") async def auth_callback(code: str, request: Request) -> HTMLResponse: """Handle Google OAuth callback""" try: # Create OAuth flow flow = Flow.from_client_config( { "web": { "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "redirect_uris": [REDIRECT_URI] } }, scopes=SCOPES, redirect_uri=REDIRECT_URI ) # Exchange code for token flow.fetch_token(code=code) credentials = flow.credentials # Create token data token_data = { "access_token": credentials.token, "refresh_token": credentials.refresh_token, "token_type": credentials.token_type, "expires_at": credentials.expiry.timestamp() } # Save token data appInterface = getInterface() appInterface.saveToken("Google", token_data) # Return success page with token data return HTMLResponse( content=f""" Authentication Successful """ ) except Exception as e: logger.error(f"Error in auth callback: {str(e)}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Authentication failed: {str(e)}" ) @router.get("/me", response_model=User) @limiter.limit("30/minute") async def get_current_user( request: Request, currentUser: User = Depends(getCurrentUser) ) -> User: """Get current user information""" try: return currentUser except Exception as e: logger.error(f"Error getting current user: {str(e)}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to get current user: {str(e)}" ) @router.post("/logout") @limiter.limit("10/minute") async def logout( request: Request, currentUser: User = Depends(getCurrentUser) ) -> Dict[str, Any]: """Logout current user""" try: appInterface = getInterface(currentUser) appInterface.logout() return {"message": "Logged out successfully"} except Exception as e: logger.error(f"Error during logout: {str(e)}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to logout: {str(e)}" )