Implementing OAuth 2.0 with Google Drive using FastAPI

Implementing OAuth 2.0 with Google Drive using FastAPI

What is OAuth 2.0 and why is it necessary? 

OAuth 2.0 is a popular method for allowing third-party apps to access user data without needing passwords, commonly used for services like Google Drive. Instead of passwords, OAuth 2.0 uses tokens for secure permission, which avoids storing sensitive login details and enhances security.

This blog covers implementing OAuth 2.0 with Google Drive in Python and FastAPI. It explains how to set up credentials and includes code for listing and downloading files from Google Drive, giving a clear example of how to connect FastAPI to Google Drive using OAuth.

Setting Up The Project

Step 1: Install Required Libraries

pip install google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client fastapi uvicorn        

Step 2: Setting up OAuth Credentials in Google Cloud Console

  1. Create a Project:

2. Enable Google Drive API:

  • Navigate to APIs & Services > Library, search for "Google Drive API," and enable it.

3. Set Up OAuth Consent Screen:

  • Go to APIs & Services > OAuth consent screen.
  • Select User Type: Choose External
  • App Information: Enter the required details such as App Name, User Support Email, and Developer Contact Information.
  • Scopes: Click ‘Add or remove scopes’ and include the required scopes. For this tutorial, the scope needed is:  https://www.googleapis.com/auth/drive.readonly
  • Test Users : Specify the users who are permitted to authenticate and use the app during testing. 
  • Save and Continue.

4. Create OAuth Credentials:

  • Go to APIs & Services > Credentials, click Create Credentials, and choose OAuth Client ID.
  • Select Desktop App.
  • Download the client_secret.json file and save it in the project directory.


Step 3: Code Implementation

Create a main.py file with the following endpoints:

  • /auth Endpoint: Authenticates users via Google OAuth and stores credentials in token.json to allow re-use.
  • /drive/list Endpoint: Lists files in Google Drive by using the Google Drive API, returning file IDs and names.
  • /drive/download/{file_id} Endpoint: Downloads a specific file from Google Drive using the provided file ID.

# Necessary imports
import os
import io
from fastapi import FastAPI
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload


# Initialize FastAPI app
app = FastAPI()


# Google OAuth 2.0 scopes for Google Drive
SCOPES = ["https://www.googleapis.com/auth/drive.readonly"]
        

  • SCOPES define the level of access the app requires (e.g., read-only access to Google Drive).

File paths for OAuth token and client secrets

# File paths for token storage
TOKEN_FILE_PATH = "token.json"
CLIENT_SECRET_FILE = "client_secret.json"        

These paths refer to where the token and client secret files will be stored. The client_secret.json file contains the OAuth credentials. The token.json stores the OAuth token, allowing the application to reuse it without requiring repeated logins.

load_creds() Function

  • To avoid asking user to login each time, credentials are stored in a file and reused unless the token has expired. If the token expires, it can be refreshed using the refresh method.

def load_creds():
   """Load and refresh credentials if necessary."""
   if os.path.exists(TOKEN_FILE_PATH):
       creds = Credentials.from_authorized_user_file(TOKEN_FILE_PATH, SCOPES)
       if creds and creds.expired and creds.refresh_token:
           creds.refresh(Request())
           with open(TOKEN_FILE_PATH, "w") as token_file:
               token_file.write(creds.to_json())
       return creds
   return None        

auth() Endpoint

@app.get("/auth")
async def auth():
   """Perform authentication and return a success message."""
   creds = load_creds()
   if not creds:
       flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, SCOPES)
       creds = flow.run_local_server(port=0)  
       with open(TOKEN_FILE_PATH, "w") as token_file:
           token_file.write(creds.to_json())

   return {"message": "Successfully logged in."}        

The /auth endpoint begins the OAuth process. It uses the InstalledAppFlow class from google_auth_oauthlib to handle authentication. A browser window opens where the user logs into their Google account and grants permissions. After authorization, the app gets an access token, which is saved in token.json for future use.

list_files() Endpoint

@app.get("/drive/list")
async def list_files():
   """List all files from Google Drive."""
   creds = load_creds()
   if not creds:
       return {"message": "User not authenticated."}

   service = build("drive", "v3", credentials=creds)

   # List files with the required fields (id, name)
   results = service.files().list(fields="files(id, name)").execute()

   items = results.get("files", [])

   # Collect file information (id, name)
   files_with_info = [{"id": item["id"], "name": item["name"]} for item in items]

   return files_with_info        

  • The build("drive", "v3", credentials=creds) creates a connection to the Google Drive API, allowing the app to access and retrieve files from the user's Drive with their authorized credentials.
  • The service.files().list() fetches and returns the file IDs and names from Google Drive.

download_file() Endpoint

@app.get("/drive/download/{file_id}")
async def download_file(file_id: str):
   """Download a specific file from Google Drive."""
   creds = load_creds()
   if not creds:
       return {"message": "User not authenticated."}

   service = build("drive", "v3", credentials=creds)
   request = service.files().get_media(fileId=file_id)
   file_name = service.files().get(fileId=file_id).execute().get("name")

   fh = io.BytesIO()
   downloader = MediaIoBaseDownload(fh, request)
   done = False
   while not done:
       status, done = downloader.next_chunk()

   fh.seek(0)
   with open(file_name, "wb") as file:
       file.write(fh.read())

   return {"message": f"File '{file_name}' downloaded successfully."}        

  • The build("drive", "v3", credentials=creds) creates a connection to the Google Drive API.

  • A get_media request is made to fetch the file content based on the provided file_id.

Step 4: Running the FastAPI Application

To start the application, use:  uvicorn main:app --reload                                                                Access the Swagger UI at http://localhost:8000/docs to test the endpoints directly.

Conclusion

This guide demonstrates how to implement OAuth 2.0 in FastAPI to connect to Google Drive for listing and downloading files. This foundation can be adapted to access other Google services by adjusting the OAuth scopes.


To view or add a comment, sign in

More articles by Inspiring Lab

Others also viewed

Explore content categories