from fastapi import APIRouter, HTTPException, Request from fastapi.responses import RedirectResponse from datetime import datetime, timedelta import httpx import os import jwt from api.database.mongodb import users_collection router = APIRouter(prefix="/auth/google", tags=["auth"]) GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID") GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET") REDIRECT_URI = os.getenv("GOOGLE_REDIRECT_URI") SECRET_KEY = os.getenv("SECRET_KEY") FRONTEND_URL = os.getenv("FRONTEND_URL", "http://localhost:5173") @router.get("/login") async def google_login(): google_auth_url = ( "https://accounts.google.com/o/oauth2/auth" "?response_type=code" f"&client_id={GOOGLE_CLIENT_ID}" f"&redirect_uri={REDIRECT_URI}" "&scope=openid%20email%20profile" "&access_type=offline" "&prompt=consent" ) return RedirectResponse(google_auth_url) @router.get("/callback") async def google_callback(request: Request): code = request.query_params.get("code") if not code: raise HTTPException(status_code=400, detail="Missing code parameter") token_url = "https://oauth2.googleapis.com/token" data = { "code": code, "client_id": GOOGLE_CLIENT_ID, "client_secret": GOOGLE_CLIENT_SECRET, "redirect_uri": REDIRECT_URI, "grant_type": "authorization_code", } async with httpx.AsyncClient() as client: token_response = await client.post(token_url, data=data) token_json = token_response.json() if "access_token" not in token_json: raise HTTPException(status_code=400, detail=token_json) access_token = token_json["access_token"] async with httpx.AsyncClient() as client: userinfo = await client.get( "https://www.googleapis.com/oauth2/v2/userinfo", headers={"Authorization": f"Bearer {access_token}"} ) user_data = userinfo.json() google_id = user_data["id"] email = user_data["email"] name = user_data.get("name", "Usuario") user = await users_collection.find_one({"email": email}) if not user: new_user = { "username": name, "email": email, "password_hash": None, "google_id": google_id, "history": [], } result = await users_collection.insert_one(new_user) user_id = result.inserted_id else: user_id = user["_id"] token = jwt.encode( { "sub": str(user_id), "email": email, "name": name, "exp": datetime.utcnow() + timedelta(hours=24) }, SECRET_KEY, algorithm="HS256" ) await users_collection.update_one( {"_id": user_id}, {"$set": {"token": token}} ) return RedirectResponse(f"{FRONTEND_URL}/login?token={token}")