Sécuriser Google Cloud Endpoints avec Auth0

Google Cloud Endpoints (GCE) est un système de gestion d’API offrant des fonctionnalités pour vous aider à créer, maintenir et sécuriser vos API. GCE utilise OpenAPI pour définir les points de terminaison, les entrées et les sorties, les erreurs et la description de la sécurité de votre API.

Pour plus d’informations sur la spécification OpenAPI, voir le référentiel de spécification OpenAPI sur GitHub.

Ce tutoriel explique comment sécuriser Google Cloud Endpoints avec Auth0.

Prérequis

Avant de commencer, vous aurez besoin d’une API GCE déployée. Si vous n’avez pas encore créé d’API, suivez le Guide de démarrage rapide de Cloud Endpoints qui se trouve dans la documentation de Google.

Le guide de démarrage rapide vous guidera à travers la création d’une API GCE simple avec un seul point de terminaison, /airportName, qui renvoie le nom d’un aéroport à partir de son code IATA de trois lettres.


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?

/

Définir l’API dans Auth0

Allez dans Tableau de bord Auth0 > Applications > API, et créez une nouvelle API.

Dashboard – Créer API – Intégrations – Points finaux Google

Notez l’identifiant d’audience de l’API (http://google_apidans la capture d’écran ci-dessus) à utiliser à l’étape suivante.

Mettre à jour la configuration de l’API

Ensuite, nous mettrons à jour le fichier de configuration OpenAPI pour l’API GCE. Pour l’exemple d’API créé lors du démarrage rapide, ce fichier est openapi.yaml.

Ajouter des définitions de sécurité

Ouvrez le fichier de configuration et ajoutez une nouvelle section securityDefinitions. Dans cette section, ajoutez une nouvelle définition (auth0_jwt) avec les champs suivants :

Champ Description
authorizationUrl L’URL d’autorisation, doit être définie sur "https://{yourDomain}/authorize"
flow Le flux utilisé par le schéma de sécurité OAuth2. Les valeurs valides sont "implicit", "password", "application" ou "accessCode".
type Le type du schéma de sécurité. Les valeurs valides sont "basic", "apiKey" ou "oauth2"
x-google-issuer L’émetteur d’un identifiant, doit être défini sur "https://{yourDomain}/"
x-google-jwks_uri L’URI de la clé publique définie pour valider la signature JSON Web Token (JWT). Définissez ceci sur "https://{yourDomain}/.well-known/jwks.json"
x-google-audiences L’identifiant de l’API, assurez-vous que cette valeur correspond à ce que vous avez défini dans Auth0 Dashboard pour l’API.

codeblockOld.header.login.configureSnippet
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?

/

Mettre à jour le point de terminaison

Maintenant, mettez à jour le point de terminaison en ajoutant un champ security avec la section securityDefinition que nous avons créée à l’étape précédente.

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?

/

Dans l’exemple ci-dessus, le champ security indique au proxy GCE que notre chemin /airportName s’attend à être sécurisé avec la définition auth0-jwt.

Après la mise à jour de la configuration OpenAPI, elle devrait ressembler à ceci :

codeblockOld.header.login.configureSnippet
---
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?

/

Redéployer l’API

Ensuite, redéployez votre API GCE pour appliquer les changements de configuration. Si vous avez suivi le Guide de démarrage rapide de Cloud Endpoints, vous pouvez redéployer l’API en saisissant les éléments suivants dans le Cloud Shell de Google :

cd endpoints-quickstart/scripts
./deploy_api.sh

Was this helpful?

/

Tester l’API

Une fois que vous avez redéployé l’API, appelez à nouveau l’API sans sécurité.


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?

/

Vous obtiendrez la réponse suivante :

{
 "code": 16,
 "message": "JWT validation failed: Missing or invalid credentials",
 "details": [
  {
   "@type": "type.googleapis.com/google.rpc.DebugInfo",
   "stackEntries": [],
   "detail": "auth"
  }
 ]
}

Was this helpful?

/

Et c’est exactement ce que l’on veut!

Accédez maintenant à la page Test de la définition de votre API Google Endpoints sur le Auth0 Dashboard et copiez le jeton d’accès sous la réponse :

Effectuez une demande GET à votre API avec un en-tête d’autorisation du Bearer {ACCESS_TOKEN} pour obtenir un accès autorisé :


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?

/

Et voilà!