Securing Backend APIs with GCP API Gateway and Auth0

You've had your billion dollar, unicorn start-up idea. Your mind is already racing with the architecture, frontend and backend code you'll need to make it a reality. Your main business logic will be served by the backend code. This will (usually) be accessed through RESP APIs that you've so lovingly and tenderly handcrafted with a sweet kiss on the forehead that only a loving mother could hope to replicate.
Now, time to secure your precious childre- I mean APIs, from potential harm...
Background
This guide will make use of Auth0 as an identity broker for a few reasons
- It's easy. Offload your identity and principal management to somebody else
- Auth0 provides rich libraries for handling Users, registrations, SSO, password resets and, most importantly for this post, accessTokens in a straightforward manner
We'll also be using Google Cloud's API Gateway as that's what I've experimented with and written a previous post on for handling CORS preflight checks - read about that here:

Pre-requisites
You'll need to create an Auth0 application suitable for your Front End. Once that's created, Navigate to Applications > Applications and select your newly created app. In the below screen, you'll see your Domain
. Make a note of this!

Under Applications > API, you'll also need to create an API to represent your endpoints. Once done, make a note of the Identifier
(Audience
) that you will have provided during creation:

You should now have a note of your:
Auth0 Domain
Auth0 API Audience
You'll also need your Front End application to handle Auth0 login and send your Auth0 User's accessToken (this is important!) with each request. There is documentation on getting this for a number of frameworks, pick your poison.
Implementation
Once you've got the pre-requisites, the implementation is rather simple. Using the OpenAPI Spec YAML file, we can setup a security attribute and apply it to all of the endpoints we want to secure.
Here is a full example that we'll break down:
# openapi-spec.yaml
swagger: "2.0"
info:
title: "Voqu VBaaS Backend API"
description: "API for the Voicebot-as-a-Service platform"
version: "1.0.0"
schemes:
- "https"
produces:
- "application/json"
host: "${api_gateway_managed_service}"
x-google-endpoints:
- name: "${api_gateway_managed_service}"
allowCors: True
securityDefinitions:
auth0_jwt:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://${auth0_domain}/"
x-google-jwks_uri: "https://${auth0_domain}/.well-known/jwks.json"
x-google-audiences: "${auth0_api_audience}"
# We are returning to the path-based approach, now with the validator exception.
paths:
/hello:
get:
description: "A sample endpoint to test authentication."
operationId: "hello"
x-google-backend:
address: "my-super-cool-url.highoncloud.co.uk/hello"
security:
- auth0_jwt: []
responses:
"200":
description: "A successful response"
Remember, this is YAML so be careful with spacing. The above file uses 2-space indents.
The 2 aspects we're using to secure our endpoints in the above file are:
securityDefinitions
- This block defines how the security will be checked, the JWT token issuer, URI and defined audiencessecurity
- This block is defined as a parameter in each endpoint method that we wish to secure allowing modular application of security where required
The entire flow works as follows:
- The request reaches GCP API gateway with a header of
Authorization: Bearer {token}
as is the standard for Access Tokens - GCP API Gateway sees that the endpoint being accessed (
GET on /hello
) has a security parameter so it expects a Token to be checked before allowing the request to pass through - The GCP API gateway takes the provided token and uses the auth0 domain, JWKS URI and audiences to validate that the token belongs to a valid Auth0 user and contains the correct claims.
- If all checks succeed, the request is forwarded to the backend.
- If the checks fail i.e. the JWT token has expired or does not contain all of the correct, required claims, an error 401 Unauthorized is returned.
Deployment
For deployment, this guide uses terraform.
The below snippets creates everything you need. Ensure your API Spec YAML file is in your main terraform directory alongside the below code.
- Enable the API Gateway Service
resource "google_project_service" "apigateway" {
project = var.project_id
service = "apigateway.googleapis.com"
disable_on_destroy = false
}
- Create the Gateway API Resource as a container for the YAML configuration
resource "google_api_gateway_api" "vbaas_api" {
provider = google-beta # API Gateway resources are often updated in the beta provider
project = var.project_id
api_id = "vbaas-backend-api"
display_name = "VBaaS Backend API"
depends_on = [google_project_service.apigateway]
}
- Store the OpenAPI Spec YAML file and pass in the required variables
resource "google_api_gateway_api_config" "vbaas_api_config" {
provider = google-beta
project = var.project_id
api = google_api_gateway_api.vbaas_api.api_id
api_config_id_prefix = "vbaas-config-"
display_name = "Voqu VBaaS Config v1.0.0"
openapi_documents {
document {
path = "openapi-spec.yaml"
contents = base64encode(templatefile("${path.module}/openapi-spec.yaml", {
auth0_domain = var.auth0_domain
auth0_api_audience = var.auth0_api_audience
api_gateway_managed_service = var.api_gateway_managed_service
}))
}
}
# This lifecycle rule prevents downtime during updates by creating the new
# config before destroying the old one.
lifecycle {
create_before_destroy = true
}
}
- Spin up the API Gateway
resource "google_api_gateway_gateway" "vbaas_gateway" {
provider = google-beta
project = var.project_id
region = var.region
gateway_id = "vbaas-gateway"
api_config = google_api_gateway_api_config.vbaas_api_config.id
display_name = "Voqu VBaaS Gateway"
depends_on = [google_api_gateway_api_config.vbaas_api_config]
}
- <Optional> Add an output to easily find your API Gateway URL
output "api_gateway_url" {
description = "The default hostname of the deployed API Gateway."
value = "https://${google_api_gateway_gateway.vbaas_gateway.default_hostname}"
}
Conclusion
Now, you can use Auth0 credentials to manage access to your backend APIs. The flexibility of this approach means that the security requirement can be added to any API endpoints and even specific HTTP Request methods for that endpoint, as and when required.