26/01/2015

Transparent access (login) to Google API v3

Login, API, Google

Josep Sanz, Jordi Company

From the November 17, 2014, the access to the Google's API v1 and v2 services have stopped working forcing all developers to migrate their code to the new API v3 (https://developers.google.com/api-client-library/php/). In SaltOS, like other applications, we had to make this change and it makes everything work.

Previously, access to the service could be obtained using the user+password for the service account. Currently this no longer works well, but must obtain a token that will allow us to use the service in future access until the user revokes the token. For this it is necessary to create a key from the console of the google developers. There are 2 types: for online application and therefore will be linked to a host, or application installed, which is not associated with a host. This second case is that we have used to create the key to access the service because the first not worth us.

Currently, when it is necessary that the user is authenticated, the API proposes to redirect our page to Google where you should follow three steps:

1) If you are not logged into Google, it asks the email and password to Google.
2) You are asked if you want to give permission for the application to access data on the desired application (Google Calendar in the SaltOS's case).
3) A screen appears with a text box containing the token and explain to the user that must to copy and paste the core into the application.

If the key has an associated host, point 3 is automatic, because it is redirected to the host passing the token as parameter. In our case we have created a key for installed application and no host redirection works.

As you can see, it is a tedious process for the user, and from SaltOS, we have programed a solution to automate this process caused by the lack of a mechanism for direct authentication from Google API v3. The "trick" is to make the steps that Google want to get the token (token1 onwards) by programmatically.

This token must be passed to the google client authenticate method and this will get the second token (token2 onwards) which will be used in future requests to access the service. To summarize:

1) If we have not the token2, we get the token1 user+password and authenticate. The token2 used in future requests will be obtained using the getAccessToken.
2) if we have the token2, we use it to authenticate using setAccessToken

To do this, SaltOS defines the following functions:

function __gcalendar_getattr($html,$attr)

This function returns the value of the first attribute in $html. For example, if you pass $html a node <form> and pass in $attr the string "method", it returns GET or POST.

function __gcalendar_getnode($html,$name)

This function returns the portion of $html code that tag is $name. For example, if you pass an html form node and the node <form> is requested, this function will return the html code from <form> to </form> with everything that contains this form.

function __gcalendar_parse($html)

This function returns an array with 3 data elements from the first form found in $html:

1) method.
2) action.
3) An array with a list of key=>value where key is the name of the inputs and value are the values of the inputs
.
function __gcalendar_request($url,$method="",$values=array(),$cookies=array(),$referer="")

This function uses an used SaltOS's class (http://www.phpclasses.org/package/3-PHP-HTTP-client-to-access-Web-site-pages.html) which allows http requests quickly.

This function makes a request to the $url, using the $method, sending variables array $values, using the cookies contained in the $cookies array and using as referer the $referer variable. Returns an array with 3 elements:

1) The body.
2) An array with the headers.
3) An array with cookies.

function __gcalendar_token1($client,$login,$password) {
    $url=$client->createAuthUrl();
    list($body,$header,$cookies)=__gcalendar_request($url);
    // PROCESS LOGIN PAGE
    $parsed=__gcalendar_parse($body);
    $parsed["inputs"]["Email"]=$login;
    $parsed["inputs"]["Passwd"]=$password;
    $parsed["inputs"]["continue"]=str_replace("&","&",$parsed["inputs"]["continue"]);
    list($body,$header,$cookies)=__gcalendar_request($parsed["action"],$parsed["method"],$parsed["inputs"],$cookies,$url);
    // PROCESS ACCEPT PAGE
    $url=$parsed["action"];
    $parsed=__gcalendar_parse($body);
    $parsed["action"]=str_replace("&","&",$parsed["action"]);
    $parsed["inputs"]["submit_access"]="true";
    list($body,$header,$cookies)=__gcalendar_request($parsed["action"],$parsed["method"],$parsed["inputs"],$cookies,$url);
    // PROCESS TOKEN PAGE
    $html=__gcalendar_getnode($body,"input");
    $token1=__gcalendar_getattr($html,"value");
    return $token1;
}

This function is the most interesting of the whole explanation, because using the above functions, manages to get the first token to access Google Calendar service.

To do what it does is:

1) Get the url authentication $client object
2) Make the first request. This first request will get the HTML code of the page you requested that ask email and password to access Google.
3) Obtain the action, method and list of variables of the form from the resulted body.
4) Set the Email and Passwd inputs of the form
5) The second request with action, method and list of modified variables. This second request will get the HTML code of the page that prompts the user for permission to access Google Calendar.
6) Obtain the action, method and list of variables of the form from the resulted body.
7) Set "true" to the "submit_access" input
8) The third reqiest with the action, method and list of modified variables. This will return an html page with an input containing the token we need.
9) In the body of the results, we get the node <input> and from it node, gets the value of the "value" attribute. With this we have the token.

Notes:

- Point 1 is simple using Google API v3
. - In sections 2, 5 and 8 are 3 requests to pages that need (access to google, permission to the application and obtaining token)
. - In sections 3 and 6, we get the action, method and variable list from the form
. - In sections 4 and 7, we modify the form (emulating user interaction)
. - Point 9 is to process the results page
.
function __gcalendar_connect($login,$password) {
    $client=new Google_Client();
    $client->setAuthConfigFile("lib/google/saltos.json");
    $client->setRedirectUri("urn:ietf:wg:oauth:2.0:oob");
    $client->addScope("https://www.googleapis.com/auth/calendar");
    $client->setAccessType("offline");
    $token2=execute_query(make_select_query("tbl_gcalendar","token2",make_where_query(array(
        "id_usuario"=>current_user()
    ))));
    if($token2!="") {
        $client->setAccessToken(base64_decode($token2));
        if($client->getAccessToken()) return $client;
    }
    $token1=__gcalendar_token1($client,$login,$password);
    if($token1=="") return null;
    $client->authenticate($token1);
    $token2=$client->getAccessToken();
    if(!$token2) return null;
    $query=make_update_query("tbl_gcalendar",array(
        "token2"=>base64_encode($token2)
    ),"id_usuario='".current_user()."'");
    db_query($query);
    return $client;
}

This function returns an object that will allow to access to the Google Calendar service.

Create a Google_Client object, sets the file that contains the key created for our project, set where we want access, access type and:

1) If we already have a token2 in the database, we use it to authenticate yourself by setAccessToken. If this is valid through getAccessToken, return the $client.
2) If token2 is invalid or does not exist, we call the above function (__gcalendar_token1) that by the above trick we return the token1 access for get the token2.
3) With the above token1, call the authenticate function and obtain the token2 by getAccessToken.
4) If all went well and we have already token2, we will keep in the database to reuse the token2 in future SaltOS requests.

More info:

For more details about what I explained here, you can see the SaltOS's source code and in particular the file php/action/gcalendar.php

XML lines
60,895
PHP lines
18,637
JS lines
11,620
XSLT lines
2,498
CSV lines
1,919
CSS lines
577

© The SaltOS project, http://www.saltos.org | Legal note