'Python / GCP - GitHub Action & Google OAuth without committing ID

For a project using the YouTube API, I am using a function that reads my OAuth 2.0 ID from a JSON file, creates / refreshes the credentials automatically and then generate a service to perform all kind of API requests. I've been running the script locally for a few days now, without any problems. But now I would like to automate my project using GitHub Action and specific triggers.

My function looks roughly like this:

import ast
import googleapiclient.discovery
import googleapiclient.errors
import json
import os
import sys

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow

def get_authenticated_service():
    # OAUTH 2.0 ID path
    oauth_file = '../tokens/oauth.json'
    scopes = ["https://www.googleapis.com/auth/youtube.force-ssl"]
    cred = None

    if os.path.exists('../tokens/credentials.json'):
        # Retrieve credentials
        cred = Credentials.from_authorized_user_file('../tokens/credentials.json')

    if not cred or not cred.valid:  # Cover outdated credentials
        if cred and cred.expired and cred.refresh_token:
            cred.refresh(Request())

        else:
            # Create a Flow from 'oauth_file'
            flow = InstalledAppFlow.from_client_secrets_file(oauth_file, scopes)
            # Run authentification process
            cred = flow.run_local_server()

        with open('../tokens/credentials.json', 'w') as cred_file:
            # Save credentials as a JSON file
            json.dump(ast.literal_eval(cred.to_json()), cred_file, ensure_ascii=False, indent=4)

    try:
        service = googleapiclient.discovery.build('youtube', 'v3', credentials=cred)
        return service

    except Exception as error:
        sys.exit()

The problem is that I share my code with a public repository and I don't want to share / commit my ID (what is in token folder). I'm just starting to learn how GitHub Action works and I have no idea of how to transpose my current method to something that might do the job in a workflow. Is this even possible?



Solution 1:[1]

Following @DazWilkin's answer, I found a way to use the Google API Python Client using a Workflow Identity Federation. It took me a while to figure out how all of this is working, but now I can provide an answer. And "surprisingly", it's quite simple to set up.

After setting-up your Federation, you can add these authentication lines in the desired workflow (YAML file):

steps:
    -   id: checkout
        name: Checkout repository
        uses: actions/checkout@v3
    
    -   id: auth
        name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v0
        with:
            token_format: 'access_token'
            access_token_scopes: 'https://www.googleapis.com/auth/youtube.force-ssl'
            workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
            service_account: '[email protected]'
        
# TODO: Install dependencies, program execution...

The service's creation with the Python client is then done with the google.auth's default method:

import google.auth
import googleapiclient.discovery

def create_service_workflow():
    scopes = ["https://www.googleapis.com/auth/youtube.force-ssl"]
    credentials, _ = google.auth.default(scopes=scopes)
    service = googleapiclient.discovery.build('youtube', 'v3', credentials=credentials)
    return service

Solution 2:[2]

You should be able to use Workflow Identity Federation in GitHub Actions.

Your code should use a Service Account to authenticate instead of the installed app flow and it will need to use the Service Account flow when run as a GitHub Actions (because there's no way for a human user to intervene in the OAuth approval flow).

See Google's blog post Enable keyless auth from GitHub Actions

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 dyl_m
Solution 2 DazWilkin