Oauth2 et la librairie php de google

OAuth2 et la librairie PHP de Google

Cette page fait suite à notre article "Google Calendar sur votre Yocto-MaxiDisplay" qui explique comment afficher les événements d'un calendrier Google sur un Yocto-MaxiDisplay. Le but de cette page de détailler comment utiliser l'API Google depuis un callback HTTP qui est appelé par un YoctoHub ou un VirtualHub.

OAuth2.0


Pour pouvoir utiliser l'API de Google, il faut autoriser le script PHP à utiliser les données de l'utilisateur à l'aide du protocole OAuth 2.0. Le protocole OAuth 2.0 permet à un site client (notre script PHP) d'accéder à des données privées d'un site fournisseur (Google) sans que L'utilisateur ne fournisse son mot de passe au site client (notre script PHP). Concrètement, chaque application web qui utlise un service Goole doit passer en paramètre un "access token" qui lui est propre pour toutes les requête à Google. Cela permet à l'utilisateur (ou Google) de révoquer l'access token d'une application sans affecter les autres applications qui utilisent le même service.

Pour obtenir cet "access token", il faut rediriger l'utilisateur sur une page hébergée chez Google pour qu'il (l'utilisateur) se logge (sur le site de Google et non le notre) et autorise notre application à accéder au service demandé (dans notre exemple Google Calendar). Si l'utilisateur autorise notre application à utiliser son agenda, Google redirigera l'utilisateur sur notre site web en passant en paramètre un "authorisation code" (valable qu'une seule fois) qui permet de récupérer un "access token".

Une fois que l'on a un "access token", il faut le sauvegarder pour ne pas avoir à demander à nouveau l'autorisation à l'utilisateur.

La séquence d'autorisation OAuth 2.0
La séquence d'autorisation OAuth 2.0



Pour résumer, il y a quatre étapes pour autoriser un script auprès de Google:

  1. La première fois que l'utilisateur se connecte, il faut le rediriger chez Google pour qu'il autorise notre script à se connecter à son calendrier.
  2. Quand l'utilisateur a autorisé notre script à se connecter à son calendrier, Google redirige l'utilisateur sur notre script avec un "authorisation code".
  3. Le script détecte l'authorisation code et envoie une requête à Google pour échanger ce code contre un "access token" et un "refresh token".
  4. On sauve les deux tokens dans la base de données.


Pour compliquer encore un peu plus les choses, les acces tokens expirent, et il faut renégocier un nouvel access token à l'aide d'un refresh token qui n'est fournit que lors du premier échange de token.

Lorsque l'access token expire il faut en demander un nouveau à l'aide du refresh token
Lorsque l'access token expire il faut en demander un nouveau à l'aide du refresh token



Une fois que l'on est en possession de ces deux tokens, il est possible d'effectuer autant de requêtes que l'on veut à Google pour autant que les requêtes viennent du même serveur et que l'utilisateur ne révoque pas notre application.

Stocker les tokens


Avant d'appeler les fonctions de l'API Google, il faut être capable de stocker les tokens entre chaque exécution. Dans ses exemples, Google utilise les variables de session. Cette solution fonctionne parfaitement si on utilise un browser Web qui gère correctement les cookies, mais le YoctoHub ne supporte pas cette option. Il faut donc sauver les tokens dans un fichier ou dans une base de données. Il faudra donc implémenter trois fonctions (clearTokenInDb, updateTokenInDb, getTokenFromDb).

Le script PHP


La première étape est d'instancier un objet Google_Client avec les paramètres que nous trouvons dans la "Developers Console". Il est très important de ne pas oublier d'appeler setAccessType('offline') sans quoi Google ne fournira pas de "refresh token" lors de l'autorisation et il faudra demander à nouveau à l'utilisateur d'autoriser notre script quand l'access token expirera.

  $client = new Google_Client();
  $client->setApplicationName("Mon appliation");
  $client->setAccessType('offline');
  $client->setClientId('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
  $client->setClientSecret('XXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
  $client->setRedirectUri('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
  $client->addScope("https://www.googleapis.com/auth/calendar.readonly");



La première chose à faire est de vérifier si nous avons un code passé en argument sur l'URL. Si c'est le cas, c'est que l'utilisateur vient d'autoriser notre script auprès de Google et qu'il vient d'être redirigé sur notre script. Le paramètre $_GET['code'] contient l'authorisation code, retourné par Google. A l'aide de la méthode authenticate on échange ce code contre un access token et un refresh token. Il faut impérativement sauver ces deux tokens, sinon on ne pourra pas accéder à l'API Google lors de la prochaine exécution. Une fois que l'on a sauvé les tokens, on redirige à nouveau l'utilisateur sur notre script pour "nettoyer" l'URL du paramètre "code".

  if (isset($_GET['code'])) {
    $client->authenticate($_GET['code']);
    $access_token = $client->getAccessToken();
    $tokens_decoded = json_decode($access_token);
    $refreshToken = $tokens_decoded->refresh_token;
    updateTokenInDb(..., $access_token, $refreshToken);
    $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
  }



Si aucun access token n'est stocké dans la base de données, c'est que l'utilisateur n'a pas encore autorisé notre script. Dans ce cas, on appel la méthode createAuthUrl() qui retourne une URL qui permet à l'utilisateur d'autoriser notre script.

  $access_token = getTokenFromDb(...);
  if(!$access_token) {
    /**
    * AUCUN TOKEN SAUVE -> IL FAUT REDIRIGER
    * L'UTILISATEUR SUR L'URL $authUrl
    */

    $authUrl = $client->createAuthUrl();
    print_link($authUrl);
    die();
  }



Au contraire, si nous avons dans la base de données un access token, il faut l'assigner à l'objet Google_Client avec la méthode setAccessToken(). Il faut aussi vérifier que l' access token est toujours valide. Si il a expiré, il faut utiliser la méthode refreshToken() pour renégocier un nouvel access token. Cette méthode prend en argument le refresh token que nous avons sauvé lors du premier échange de token. On peut ensuite utiliser la libraire de Google pour accéder à tous les services que l'utilisateur à autorisé.

  $client->setAccessToken($access_token['access_token']);
  if ($client->isAccessTokenExpired()) {
    $client->refreshToken($access_token['refresh_token']);
  }
  /**
  * ON PEUT UTILISER L'API GOOGLE
  * ET AFFICHER LES RESULTATS
  */

  ...




A la fin, il ne faut pas oublier de mettre à jour la base de données avec les tokens valides (ceux que la librairie a utilisés).

  $access_token = $client->getAccessToken();
  $tokens_decoded = json_decode($access_token);
  $refreshToken = $tokens_decoded->refresh_token;
  updateTokenInDb($access_token, $refreshToken);



Yoctopuce, get your stuff connected.