Software Development

Google OIDC token generation/validation

One of the authentication protocol that is supported by most of Google Cloud services is OpenID Connect (OIDC). For instance, you can secure communication between a Cloud Task and HTTP-triggred Cloud Function using it quite easily. You just need to pass service account email when submitting Cloud Task job and make sure you keep the default authentication for HTTP Cloud Function. You can also expect similar setup when using Cloud Scheduler and HTTP-triggered Cloud Run: the triggerring service will automatically generate OIDC token while the triggered service will automatically validate them ?

Now the catch is more flexible services like App Engine and Compute Engine don’t have these feature in built. It can be understood as implementing such feature may reduce their flexibility. So, for example, if you want to use OIDC to secure communication between App Engine services, you will need to write few codes to do it manually.

This one of the method that I use to manually generate Google OIDC token for default service account using Python 3.x and google-auth==1.20.0 module:

import google.oauth2.id_token
import google.auth.transport.requests

google_request = google.auth.transport.requests.Request()
url = "https://myproject.appspot.com/myservice"
token = google.oauth2.id_token.fetch_id_token(google_request, url)

Once we get the token, we can make a secure HTTP request by including that token in Authorization header {"Authorization": token}.

If you want to test this script locally, make sure you export GOOGLE_APPLICATION_CREDENTIALS environment variable that contains absolute path to your service account JSON credential

Finally, this is the script I use to validate the OIDC token inside djangorestframework==3.11.0 request. I found that this script is able to validate both the token generated using script above and the one generated automatically by Cloud Task.

from rest_framework.request import Request
from google.oauth2 import id_token
from google.auth.transport import requests

def auth_request_oidc(request: Request) -> dict:
    try:
        token = request.headers["Authorization"].split(" ").pop()
        return id_token.verify_oauth2_token(token, requests.Request())
    except Exception as e:
        logger.exception(e)
        raise AuthenticationFailed()

The id_token.verify_oauth2_token() returns the JWT token payload decribed in the documentation. I think the fields/claims that we may want to validate are iss (issuer), email and email_verified. But I’m not yet experienced in JWT, so I’m not yet sure whether it is possible to forge these fields/claims. But at least, I don’t let my APIs with zero security. Right? ?

Cheers! ?

0 0 votes
Article Rating
yohanes.gultom@gmail.com

Share
Published by
yohanes.gultom@gmail.com

Recent Posts

Get Unverified SSL Certificate Expiry Date with Python

Getting verified SSL information with Python (3.x) is very easy. Code examples for it are…

3 years ago

Spring Data Couchbase 4 Multibuckets in Spring Boot 2

By default, Spring Data Couchbase implements single-bucket configuration. In this default implementation, all POJO (Plain…

4 years ago

Firebase Auth Emulator with Python

Last year, Google released Firebase Auth Emulator as a new component in Firebase Emulator. In…

4 years ago

Fast geolocation query with PostGIS

If you need to to add a spatial information querying in your application, PostGIS is…

4 years ago

Auto speech-to-text (Indonesian) with AWS Transcribe and Python

Amazon Web Service Transcribe provides API to automatically convert an audio speech file (mp3/wav) into…

5 years ago

Splitting video with ffmpeg and Python

I had a project to build a simple website that split uploaded video into parts…

5 years ago