Secure Google Cloud Endpoints with Auth0
Google Cloud Endpoints (GCE) is an API management system providing features to help you create, maintain, and secure your APIs. GCE uses OpenAPI to define your API's endpoints, input and output, errors, and security description.
For more information on the OpenAPI spec, see the OpenAPI Specification repository on GitHub.
This tutorial will cover how to secure Google Cloud Endpoints with Auth0.
Prerequisites
Before you begin you'll need a deployed GCE API. If you haven't already created an API, complete the Cloud Endpoints Quickstart located in Google documentation.
The quickstart will walk you through creating a simple GCE API with a single endpoint, /airportName
, that returns the name of an airport from its three-letter IATA code.
curl --request GET \
--url 'https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO'
Was this helpful?
var client = new RestClient("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO");
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
Was this helpful?
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
Was this helpful?
HttpResponse<String> response = Unirest.get("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
.asString();
Was this helpful?
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://%7ByourGceProject%7D.appspot.com/airportName',
params: {iataCode: 'SFO'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
Was this helpful?
#import <Foundation/Foundation.h>
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
Was this helpful?
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Was this helpful?
import http.client
conn = http.client.HTTPSConnection("")
conn.request("GET", "%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
Was this helpful?
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body
Was this helpful?
import Foundation
let request = NSMutableURLRequest(url: NSURL(string: "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
Was this helpful?
Define the API in Auth0
Go to Auth0 Dashboard > Applications > APIs, and create a new API.
Make note of the API Audience identifier (http://google_api
in the screenshot above) to use in the following step.
Update the API Configuration
Next, we'll update the OpenAPI configuration file for the GCE API. For the sample API created during the quickstart this file is openapi.yaml
.
Add Security Definitions
Open the configuration file and add a new securityDefinitions
section. In this section, add a new definition (auth0_jwt
) with the following fields:
Field | Description |
---|---|
authorizationUrl |
The authorization URL, should be set to "https://{yourDomain}/authorize" |
flow |
The flow used by the OAuth2 security scheme. Valid values are "implicit" , "password" , "application" or "accessCode" . |
type |
The type of the security scheme. Valid values are "basic" , "apiKey" or "oauth2" |
x-google-issuer |
The issuer of a credential, should be set to "https://{yourDomain}/" |
x-google-jwks_uri |
The URI of the public key set to validate the JSON Web Token (JWT) signature. Set this to "https://{yourDomain}/.well-known/jwks.json" |
x-google-audiences |
The API's identifier, make sure this value matches what you defined on the Auth0 dashboard for the API. |
securityDefinitions:
auth0_jwt:
authorizationUrl: "https://{yourDomain}/authorize"
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://{yourDomain}/"
x-google-jwks_uri: "https://{yourDomain}/.well-known/jwks.json"
x-google-audiences: "{yourApiIdentifier}"
Was this helpful?
Update the Endpoint
Now, update the endpoint by adding a security
field with the securityDefinition
we created in the previous step.
paths:
"/airportName":
get:
description: "Get the airport name for a given IATA code."
operationId: "airportName"
parameters:
-
name: iataCode
in: query
required: true
type: string
responses:
200:
description: "Success."
schema:
type: string
400:
description: "The IATA code is invalid or missing."
security:
- auth0_jwt: []
Was this helpful?
In the above example, the security
field tells the GCE proxy that our /airportName
path expects to be secured with the auth0-jwt
definition.
After updating the OpenAPI configuration, it should look something like this:
---
swagger: "2.0"
info:
title: "Airport Codes"
description: "Get the name of an airport from its three-letter IATA code."
version: "1.0.0"
host: "{yourGceProject}.appspot.com"
schemes:
- "https"
paths:
"/airportName":
get:
description: "Get the airport name for a given IATA code."
operationId: "airportName"
parameters:
-
name: iataCode
in: query
required: true
type: string
responses:
200:
description: "Success."
schema:
type: string
400:
description: "The IATA code is invalid or missing."
security:
- auth0_jwt: []
securityDefinitions:
auth0_jwt:
authorizationUrl: "https://{yourDomain}/authorize"
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://{yourDomain}/"
x-google-jwks_uri: "https://{yourDomain}/.well-known/jwks.json"
x-google-audiences: "{yourApiIdentifier}"
Was this helpful?
Redeploy the API
Next, redeploy your GCE API to apply the configuration changes. If you followed along with the Cloud Endpoints Quickstart you can redeploy by entering the following in Google's Cloud Shell:
cd endpoints-quickstart/scripts
./deploy_api.sh
Was this helpful?
Test the API
Once you've redeployed, call the API again with no security.
curl --request GET \
--url 'https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO'
Was this helpful?
var client = new RestClient("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO");
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
Was this helpful?
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
Was this helpful?
HttpResponse<String> response = Unirest.get("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
.asString();
Was this helpful?
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://%7ByourGceProject%7D.appspot.com/airportName',
params: {iataCode: 'SFO'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
Was this helpful?
#import <Foundation/Foundation.h>
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
Was this helpful?
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Was this helpful?
import http.client
conn = http.client.HTTPSConnection("")
conn.request("GET", "%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
Was this helpful?
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body
Was this helpful?
import Foundation
let request = NSMutableURLRequest(url: NSURL(string: "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
Was this helpful?
You'll get the following response:
{
"code": 16,
"message": "JWT validation failed: Missing or invalid credentials",
"details": [
{
"@type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "auth"
}
]
}
Was this helpful?
Which is exactly what we want!
Now go to the Test page of your Google Endpoints API definition on the Auth0 Dashboard, and copy the Access Token under the Response:
Perform a GET
request to your API with an Authorization Header of Bearer {ACCESS_TOKEN}
to obtain authorized access:
curl --request GET \
--url 'https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO' \
--header 'authorization: Bearer {accessToken}'
Was this helpful?
var client = new RestClient("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Bearer {accessToken}");
IRestResponse response = client.Execute(request);
Was this helpful?
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("authorization", "Bearer {accessToken}")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
Was this helpful?
HttpResponse<String> response = Unirest.get("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
.header("authorization", "Bearer {accessToken}")
.asString();
Was this helpful?
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://%7ByourGceProject%7D.appspot.com/airportName',
params: {iataCode: 'SFO'},
headers: {authorization: 'Bearer {accessToken}'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
Was this helpful?
#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"authorization": @"Bearer {accessToken}" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
Was this helpful?
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"authorization: Bearer {accessToken}"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Was this helpful?
import http.client
conn = http.client.HTTPSConnection("")
headers = { 'authorization': "Bearer {accessToken}" }
conn.request("GET", "%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
Was this helpful?
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
request["authorization"] = 'Bearer {accessToken}'
response = http.request(request)
puts response.read_body
Was this helpful?
import Foundation
let headers = ["authorization": "Bearer {accessToken}"]
let request = NSMutableURLRequest(url: NSURL(string: "https://%7ByourGceProject%7D.appspot.com/airportName?iataCode=SFO")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
Was this helpful?
And that's it!