|
"""Module for defining the main routes of the API.""" |
|
import os |
|
import json |
|
import pickle |
|
from fastapi import APIRouter, Request, HTTPException |
|
from fastapi.responses import JSONResponse |
|
from google_auth_oauthlib.flow import InstalledAppFlow |
|
from googleapiclient.discovery import build |
|
from oauthlib.oauth2.rfc6749.errors import InvalidGrantError |
|
|
|
router = APIRouter(tags=["auth"]) |
|
|
|
CLIENT_ID = os.environ.get("CLIENT_ID") |
|
CLIENT_SECRET = os.environ.get("CLIENT_SECRET") |
|
REDIRECT_URI = os.environ.get("REDIRECT_URI") |
|
|
|
SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"] |
|
|
|
|
|
CLIENT_CONFIG = { |
|
"web": { |
|
"client_id": CLIENT_ID, |
|
"client_secret": CLIENT_SECRET, |
|
"redirect_uris": [REDIRECT_URI], |
|
"auth_uri": "https://accounts.google.com/o/oauth2/auth", |
|
"token_uri": "https://oauth2.googleapis.com/token", |
|
} |
|
} |
|
|
|
@router.get("/auth/google/url") |
|
async def get_auth_url(): |
|
""" |
|
Handles the generation of a Google OAuth 2.0 authorization URL. |
|
|
|
This endpoint initializes an OAuth 2.0 flow using the provided client configuration |
|
and scopes, sets the redirect URI, and generates an authorization URL for the user |
|
to grant access. |
|
|
|
Returns: |
|
dict: A dictionary containing the generated authorization URL under the key "url". |
|
""" |
|
flow = InstalledAppFlow.from_client_config(CLIENT_CONFIG, SCOPES) |
|
flow.redirect_uri = REDIRECT_URI |
|
auth_url, _ = flow.authorization_url(access_type="offline", prompt="consent") |
|
return JSONResponse({"url": auth_url}) |
|
|
|
@router.get("/auth/google/callback") |
|
async def google_callback(code: str, state: str = None, scope: str = None, request: Request = None): |
|
try: |
|
|
|
if state and request.state.session.get("oauth_state") != state: |
|
raise HTTPException(status_code=400, detail="Invalid state parameter") |
|
|
|
flow = InstalledAppFlow.from_client_config(CLIENT_CONFIG, SCOPES) |
|
flow.redirect_uri = REDIRECT_URI |
|
flow.fetch_token(code=code) |
|
credentials = flow.credentials |
|
request.state.session["credential"] = json.loads(credentials.to_json()) |
|
|
|
service = build("gmail", "v1", credentials=credentials) |
|
profile = service.users().getProfile(userId="me").execute() |
|
|
|
|
|
os.makedirs("cache", exist_ok=True) |
|
with open(f"cache/{profile['emailAddress']}.pickle", "wb") as token: |
|
pickle.dump(credentials, token) |
|
|
|
return JSONResponse(profile) |
|
except InvalidGrantError: |
|
raise HTTPException(status_code=400, detail="Invalid or expired authorization code") |
|
except Exception as e: |
|
raise HTTPException(status_code=500, detail=f"Authentication failed: {str(e)}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|