Google Sign-In pour les applications côté serveur

Pour utiliser les services Google au nom d'un utilisateur lorsque celui-ci est hors connexion, vous devez utiliser un flux hybride côté serveur dans lequel un utilisateur autorise votre application côté client à l'aide du client API JavaScript, et vous envoyez un code d'autorisation unique spécial à votre serveur. Votre serveur échange ce code à usage unique pour obtenir ses propres jetons d'accès et d'actualisation auprès de Google afin que le serveur puisse effectuer ses propres appels d'API, ce qui peut être fait hors connexion. Ce flux de code à usage unique présente des avantages en termes de sécurité par rapport à un flux purement côté serveur et par rapport à l'envoi de jetons d'accès à votre serveur.

Le flux de connexion permettant d'obtenir un jeton d'accès pour votre application côté serveur est illustré ci-dessous.

Les codes à usage unique présentent plusieurs avantages en termes de sécurité. Avec les codes, Google fournit des jetons directement à votre serveur, sans aucun intermédiaire. Bien que nous ne recommandions pas la fuite de codes, ils sont très difficiles à utiliser sans le code secret de votre client. Gardez le secret de votre client !

Implémenter le flux de code unique

Le bouton Google Sign-In fournit à la fois un jeton d'accès et un code d'autorisation. Il s'agit d'un code unique que votre serveur peut échanger avec les serveurs de Google pour obtenir un jeton d'accès.

L'exemple de code suivant montre comment suivre le flux de code unique.

Pour authentifier Google Sign-In via un flux de code unique, vous devez:

Étape 1: Créez un ID client et un code secret du client

Pour générer un ID client et un code secret du client, créez un projet dans la console Google APIs, configurez un ID client OAuth et enregistrez vos origines JavaScript:

  1. Accédez à la console Google APIs.

  2. Dans la liste déroulante des projets, sélectionnez un projet existant ou créez-en un en sélectionnant Créer un projet.

  3. Dans la barre latérale, sous "API et services ", sélectionnez Identifiants, puis cliquez sur Configurer l'écran de consentement.

    Choisissez une adresse e-mail, spécifiez un nom de produit, puis appuyez sur Save (Enregistrer).

  4. Dans l'onglet Identifiants, sélectionnez la liste déroulante Créer des identifiants, puis sélectionnez ID client OAuth.

  5. Sous Type d'application, sélectionnez Application Web.

    Enregistrez les origines à partir desquelles votre application est autorisée à accéder aux API Google, comme suit. Une origine est une combinaison unique de protocole, d'hôte et de port.

    1. Dans le champ Origines JavaScript autorisées, saisissez l'origine de votre application. Vous pouvez indiquer plusieurs origines pour permettre à votre application de s'exécuter sur différents protocoles, domaines ou sous-domaines. Vous ne pouvez pas utiliser de caractères génériques. Dans l'exemple ci-dessous, la deuxième URL peut être une URL de production.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. Le champ URI de redirection autorisé ne nécessite aucune valeur. Les URI de redirection ne sont pas utilisés avec les API JavaScript.

    3. Appuyez sur le bouton Créer.

  6. Dans la boîte de dialogue OAuth client (Client OAuth) qui s'affiche, copiez l'ID client. L'ID client permet à votre application d'accéder aux API Google activées.

Étape 2: Incluez la bibliothèque de la plate-forme Google sur votre page

Incluez les scripts suivants, qui illustrent une fonction anonyme qui insère un script dans le DOM de cette page Web index.html.

<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
  <!-- BEGIN Pre-requisites -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
  </script>
  <!-- END Pre-requisites -->

Étape 3: Initialiser l'objet GoogleAuth

Chargez la bibliothèque auth2 et appelez gapi.auth2.init() pour initialiser l'objet GoogleAuth. Spécifiez votre ID client et les niveaux d'accès que vous souhaitez demander lorsque vous appelez init().

<!-- Continuing the <head> section -->
  <script>
    function start() {
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
          // Scopes to request in addition to 'profile' and 'email'
          //scope: 'additional_scope'
        });
      });
    }
  </script>
</head>
<body>
  <!-- ... -->
</body>
</html>

Étape 4: Ajouter le bouton de connexion à votre page

Ajoutez le bouton de connexion à votre page Web et associez un gestionnaire de clics pour appeler grantOfflineAccess() afin de démarrer le flux de code à usage unique.

<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
  $('#signinButton').click(function() {
    // signInCallback defined in step 6.
    auth2.grantOfflineAccess().then(signInCallback);
  });
</script>

Étape 5: Connecter l'utilisateur

L'utilisateur clique sur le bouton de connexion et accorde à votre application les autorisations que vous avez demandées. Ensuite, la fonction de rappel que vous avez spécifiée dans la méthode grantOfflineAccess().then() reçoit un objet JSON avec un code d'autorisation. Exemple :

{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}

Étape 6: Envoyer le code d'autorisation au serveur

Le code est votre code à usage unique que votre serveur peut échanger contre son propre jeton d'accès et son jeton d'actualisation. Vous ne pouvez obtenir un jeton d'actualisation qu'après avoir présenté à l'utilisateur une boîte de dialogue d'autorisation demandant l'accès hors connexion. Si vous avez spécifié le select-account prompt dans OfflineAccessOptions à l'étape 4, vous devez stocker le jeton d'actualisation que vous récupérez pour une utilisation ultérieure, car les échanges ultérieurs renverront null pour le jeton d'actualisation. Ce flux offre une sécurité accrue par rapport à votre flux OAuth 2.0 standard.

Les jetons d'accès sont toujours renvoyés avec l'échange d'un code d'autorisation valide.

Le script suivant définit une fonction de rappel pour le bouton de connexion. Une fois la connexion établie, la fonction stocke le jeton d'accès pour une utilisation côté client et envoie le code à usage unique à votre serveur sur le même domaine.

<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
  if (authResult['code']) {

    // Hide the sign-in button now that the user is authorized, for example:
    $('#signinButton').attr('style', 'display: none');

    // Send the code to the server
    $.ajax({
      type: 'POST',
      url: 'http://example.com/storeauthcode',
      // Always include an `X-Requested-With` header in every AJAX request,
      // to protect against CSRF attacks.
      headers: {
        'X-Requested-With': 'XMLHttpRequest'
      },
      contentType: 'application/octet-stream; charset=utf-8',
      success: function(result) {
        // Handle or verify the server response.
      },
      processData: false,
      data: authResult['code']
    });
  } else {
    // There was an error.
  }
}
</script>

Étape 7: Échanger le code d'autorisation contre un jeton d'accès

Sur le serveur, échangez le code d'autorisation contre des jetons d'accès et d'actualisation. Utilisez le jeton d'accès pour appeler les API Google au nom de l'utilisateur et, éventuellement, stockez le jeton d'actualisation pour obtenir un nouveau jeton d'accès lorsqu'il expire.

Si vous avez demandé l'accès à un profil, vous obtenez également un jeton d'ID contenant les informations de profil de base de l'utilisateur.

Exemple :

Java
// (Receive authCode via HTTPS POST)


if (request.getHeader("X-Requested-With") == null) {
  // Without the `X-Requested-With` header, this request could be forged. Aborts.
}

// Set path to the Web application client_secret_*.json file you downloaded from the
// Google API Console: https://console.cloud.google.com/apis/credentials
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "/path/to/client_secret.json";

// Exchange auth code for access token
GoogleClientSecrets clientSecrets =
    GoogleClientSecrets.load(
        JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE));
GoogleTokenResponse tokenResponse =
          new GoogleAuthorizationCodeTokenRequest(
              new NetHttpTransport(),
              JacksonFactory.getDefaultInstance(),
              "https://oauth2.googleapis.com/token",
              clientSecrets.getDetails().getClientId(),
              clientSecrets.getDetails().getClientSecret(),
              authCode,
              REDIRECT_URI)  // Specify the same redirect URI that you use with your web
                             // app. If you don't have a web version of your app, you can
                             // specify an empty string.
              .execute();

String accessToken = tokenResponse.getAccessToken();

// Use access token to call API
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Drive drive =
    new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
        .setApplicationName("Auth Code Exchange Demo")
        .build();
File file = drive.files().get("appfolder").execute();

// Get profile info from ID token
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String userId = payload.getSubject();  // Use this value as a key to identify a user.
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
Python
from apiclient import discovery
import httplib2
from oauth2client import client

# (Receive auth_code by HTTPS POST)


# If this request does not have `X-Requested-With` header, this could be a CSRF
if not request.headers.get('X-Requested-With'):
    abort(403)

# Set path to the Web application client_secret_*.json file you downloaded from the
# Google API Console: https://console.cloud.google.com/apis/credentials
CLIENT_SECRET_FILE = '/path/to/client_secret.json'

# Exchange auth code for access token, refresh token, and ID token
credentials = client.credentials_from_clientsecrets_and_code(
    CLIENT_SECRET_FILE,
    ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
    auth_code)

# Call Google API
http_auth = credentials.authorize(httplib2.Http())
drive_service = discovery.build('drive', 'v3', http=http_auth)
appfolder = drive_service.files().get(fileId='appfolder').execute()

# Get profile info from ID token
userid = credentials.id_token['sub']
email = credentials.id_token['email']