DEV Community


Posted on

OAuth2 authentication for a Google Cloud Functions

What is Google Cloud Functions?

Cloud Functions is the go-to tool for FaaS (functions as a service) on Google Cloud. It has a very intuitive interface for creating functions in few minutes!

Auth options
Cloud Functions supports IAM authentication but can I authenticate the service using an OAuth2 provider?

How does it work?

Auth Flow
In the first step we retrieve the token from an OAuth2 provider (I used Keycloak but you could use another one), then we call the function through the Google API Gateway. The API Gateway supports OpenAPI2 configuration, where we need to setup the authentication. In the final step the API Gateway calls, using a service account, the Cloud Function.

Create the Cloud Function

Here we can see how to create a cloud function using gcloud command line, but the same can be achieved using the Google Cloud web interface.

git clone
cd nodejs-docs-samples/functions/helloworld/
gcloud functions deploy helloGET --runtime nodejs16 --trigger-http
Enter fullscreen mode Exit fullscreen mode

The last command asks if we want to allow unauthenticated invocations for the new function, which we don’t, so we say no.

This creates a cloud function with IAM authentication and with an http trigger.

We need to create a GCP Service Account with the Cloud Function Invoker role, we use it later.

gcloud iam service-accounts create function-invoker --display-name="function-invoker"
gcloud projects add-iam-policy-binding my-project --member="" --role="roles/cloudfunctions.invoker"
Enter fullscreen mode Exit fullscreen mode

API Gateway setup

Enable APIs

To use API Gateway we need to enable services.

gcloud services enable
gcloud services enable
gcloud services enable
Enter fullscreen mode Exit fullscreen mode

Create the API Config

API Gateway supports the OpenAPI spec. Here we need to define the right security configuration! In order to fill the correct information in this file we need to have the cloud function http trigger (x-google-backend) and the right security information (openapi-extensions).

An example below:

# openapi2-functions.yaml
swagger: '2.0'
  title: hello
  description: Sample API on API Gateway with a Google Cloud Functions backend
  version: 1.0.0
  - https
  - application/json
      summary: Greet a user
      operationId: hello
        address: -> cloud function address!
      - keycloak: []
          description: A successful response
            type: string
  # keycloak auth
    type: oauth2
    flow: implicit
    authorizationUrl: https://KEYCLOA_INSTANCE/auth/realms/test/protocol/openid-connect/auth
    x-google-issuer: https://KEYCLOA_INSTANCE/auth/realms/test
    x-google-jwks_uri: https://KEYCLOA_INSTANCE/auth/realms/test/protocol/openid-connect/certs
    x-google-audiences: test-auth-function-gcp
Enter fullscreen mode Exit fullscreen mode

Create your Gateway

Now we can create our API and Gateway.

gcloud api-gateway apis create my-api --project=my-project
gcloud api-gateway api-configs create my-config \
  --api=my-api --openapi-spec=openapi2-functions.yaml \
gcloud api-gateway gateways create my-gateway \
  --api=my-api --api-config=my-config \
  --location=us-central1 --project=my-project
Enter fullscreen mode Exit fullscreen mode


Retrieve the gateway address

gcloud api-gateway gateways describe my-gateway \
  --location=us-central1 --project=my-project
Enter fullscreen mode Exit fullscreen mode

We get the address from the response of the above command. Check for the defaultHostname field.

Get the JWT Token

I used Keycloak for this demo, so we need to insert our token url and a valid client and user credentials.

curl --request POST \
  --url https://KEYCLOAK/auth/realms/test/protocol/openid-connect/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data client_id=myclient \
  --data username=myuser \
  --data password=mypassword \
  --data grant_type=password \
Enter fullscreen mode Exit fullscreen mode

You will get a response like this:

    "access_token": "XXXXXX",
    "expires_in": 36000,
    "refresh_expires_in": 1800,
    "refresh_token": "XXXXXX",
    "token_type": "Bearer",
    "not-before-policy": 0,
    "scope": "email profile"
Enter fullscreen mode Exit fullscreen mode

We save the access token, it is needed for the next call.

Call the API

curl --request GET \
  --url \
  --header 'Authorization: Bearer XXXXXX'
Enter fullscreen mode Exit fullscreen mode

We get the "Hello World!" response :)

If we try to make the same call without the authentication bearer token we receive this message:

    "message": "Jwt is missing",
    "code": 401
Enter fullscreen mode Exit fullscreen mode

Deep Dive

If you want to learn more check out these links:

Top comments (0)