Created
September 12, 2024 19:49
Revisions
-
codingforentrepreneurs created this gist
Sep 12, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,13 @@ # YouTube OAuth Workflow for Basic API Calls Claude says: This code handles YouTube OAuth2 authentication in a Django application. Here's what's happening: The youtube_connect function initiates the OAuth2 flow. It creates a Flow object with the necessary client configuration, scopes, and redirect URI. It then generates an authorization URL and redirects the user to Google's authentication page. The youtube_callback function handles the callback after user authentication. It retrieves the authorization code from the query parameters, creates another Flow object, and attempts to exchange the code for an access token. If successful, it fetches the user's email and channel ID using the token. The function returns an HTTP response indicating success or failure of the authentication process. Both functions use environment variables for client credentials and implement security measures like HTTPS enforcement and state verification. The code also includes error handling and logging for debugging purposes. This requires the YouTube Data API enabled on your google cloud account. You also need to enable enough quotas. If you find a better solution, please let me know. I put this as a gist to maybe use in a project in the futre. Right now, the quotas are not ideal so I have opted for Google Drive + Google Scripts. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,23 @@ from google.oauth2.credentials import Credentials from googleapiclient.discovery import build def get_user_email(user_token): # using 'https://www.googleapis.com/auth/userinfo.email', # to get user's email credentials = Credentials(token=user_token.get('access_token')) userinfo_service = build('oauth2', 'v2', credentials=credentials) userinfo = userinfo_service.userinfo().get().execute() return userinfo.get('email') def get_user_channel_id(user_token): # using 'https://www.googleapis.com/auth/youtube.readonly', # to get user's channel id credentials = Credentials(token=user_token.get('access_token')) youtube_service = build('youtube', 'v3', credentials=credentials) request = youtube_service.channels().list( part='snippet', mine=True, maxResults=1 ) response = request.execute() return response.get('items', [{}])[0].get('snippet', {}).get('channelId') This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,91 @@ import os from django.http import HttpResponse from django.shortcuts import redirect from google_auth_oauthlib.flow import Flow from . import services os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '0' # Replace these with your actual client ID and secret CLIENT_ID = os.environ('GOOGLE_OAUTH2_KEY') CLIENT_SECRET = os.environ('SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET') SCOPES = [ 'https://www.googleapis.com/auth/youtube.force-ssl', 'https://www.googleapis.com/auth/youtube.readonly', 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', 'openid', ] API_SERVICE_NAME = 'youtube' API_VERSION = 'v3' def youtube_callback(request): """Requires quota""" base_url = request.build_absolute_uri('/connect/youtube/').replace( 'http:', 'https:', 1 ) redirect_uri = base_url.split('?')[0] # Remove any query parameters query_params = request.GET if 'code' in query_params: code = query_params.get('code') state = query_params.get('state') 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', } }, scopes=SCOPES, state=state, redirect_uri=redirect_uri, ) message = 'success' status = 200 try: token = flow.fetch_token(code=code) print(f'Token: {token}') message = 'Authentication successful!' status = 200 except Exception as e: print(f'Error fetching token: {str(e)}') message = f'Authentication failed: {str(e)}' status = 400 email = services.get_user_email(token) channel_id = services.get_user_channel_id(token) print(f'Profile: {email}, {channel_id}') return HttpResponse(message, status=status) def youtube_connect(request): base_url = request.build_absolute_uri('/connect/youtube/').replace( 'http:', 'https:', 1 ) redirect_uri = base_url.split('?')[0] # Remove any query parameters 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', } }, scopes=SCOPES, redirect_uri=redirect_uri, ) authorization_url, state = flow.authorization_url( access_type='offline', include_granted_scopes='true' ) request.session['state'] = state return redirect(authorization_url)