Mailbox / app /router /auth.py
gavinzli's picture
Refactor Google OAuth2 callback to include state and scope parameters in the function signature and improve logging
216bd87
"""Module for defining the main routes of the API."""
import os
import json
import pickle
from cv2 import log
from fastapi import APIRouter, Request
from fastapi.responses import JSONResponse
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
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 for OAuth flow
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(state: str, code: str, scope: str, request: Request):
"""
Handles the Google OAuth2 callback by exchanging the authorization code for credentials,
retrieving the user's Gmail profile, and saving the credentials to a file.
Args:
code (str): The authorization code returned by Google's OAuth2 server.
request (Request): The incoming HTTP request object.
Returns:
JSONResponse: A JSON response containing the user's Gmail profile information.
Side Effects:
- Saves the user's credentials to a pickle file named after their email address.
- Stores the credentials in the session state of the request.
Dependencies:
- google_auth_oauthlib.flow.InstalledAppFlow: Used to handle the OAuth2 flow.
- googleapiclient.discovery.build: Used to build the Gmail API service.
- json: Used to serialize and deserialize credentials.
- pickle: Used to save credentials to a file.
"""
print("state: ", state)
print("code: ", code)
print("scope: ", scope)
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())
# cred_dict = (request.state.session.get("credential"))
# cred = Credentials(
# token=cred_dict["token"],
# refresh_token=cred_dict["refresh_token"],
# token_uri=cred_dict["token_uri"],
# client_id=cred_dict["client_id"],
# client_secret=cred_dict["client_secret"],
# scopes=cred_dict["scopes"],
# )
# service = build("gmail", "v1", credentials=Credentials(
# token=cred_dict["token"],
# refresh_token=cred_dict["refresh_token"],
# token_uri=cred_dict["token_uri"],
# client_id=cred_dict["client_id"],
# client_secret=cred_dict["client_secret"],
# scopes=cred_dict["scopes"],
# ))
service = build("gmail", "v1", credentials=credentials)
profile = service.users().getProfile(userId="me").execute()
with open(f"cache/{profile['emailAddress']}.pickle", "wb") as token:
pickle.dump(credentials, token)
return JSONResponse(profile)