📜 ⬆️ ⬇️

How I tried to make friends with Google API with CodeIgniter A3M and what came of it



Recently, the task arose of screwing the A3M library (this is a fairly popular authentication library for CodeIgniter) to support OAuth2 authentication via Google. It all started when a comrade approached me a couple of months ago. He has a website written by someone in ancient times on CodeIgniter. Naturally, this someone has already disappeared in an unknown direction.

The site is quite working and doesn’t have any particular problems, so the comrade didn’t sweat much and didn’t even think about updates or (God forbid) migration to anywhere.
')
One day, he discovered that when logging in via Google, this message arrives:

OpenID 2.0 for Google Accounts is Going Away. OpenID 2.0 is no longer supported. If your app uses OpenID 2.0, you must migrate your app by the date of April 20, 2015, as shown in the migration schedule.

Although my friend was never a programmer, he sensed something was wrong and turned to me in the hope that I could fix this thing.
It has a rather large database of users on the site who logged in via Google, and if this business is not fixed until April 20th, many users will suddenly not be able to access the site.

“Not a problem, let's fix it,” I said, and went into the Google manual on migration . After reading the first time, I realized that everything was difficult and decided to look for simpler ways. “It’s logical,” I thought, “that the authors of A3M are also aware that Google is stopping support for OpenID 2.0 and has already rolled out the patch on GitHub.” And although the authors, in general, are aware, they have no time for that, desire / something else.

I was sent to the beta-branch, where they complete the integration of A3M with HybridAuth , which should solve all the problems of humanity logs in via OAuth2. I, of course, this very brunch logs in through Google flatly refused for all sorts of different reasons. I, in principle, could continue to sit at night with a debagger and make it work, but as time went on, April 20 inexorably approached, and I decided to look for another, more effective method.

As it turned out, the guys from Google do not lose time and they already have a ready Client API in all less known languages. Now it remains only to “introduce” A3M to google-api-php-client.

Well, for the work.

So, first download the Google API PHP Client:

git clone https://github.com/google/google-api-php-client 

Copy the entire folder into application / libraries. It remains only to connect everything beautifully.

Now go here: console.developers.google.com . Here you need to create a new project. After that, go to the API's, find the Google+ API and enable it. Then go to "Credentials" and create a "New Client ID". You must specify the correct Redirect URIs and origins JavaScript. After creation we will receive our client id and client secret.

Actually code:
Go to application / controllers / account / connect_google.php. First of all, connect the google API. It is important to specify the absolute path to the library, otherwise the composer will not be able to download all the necessary components:

 set_include_path ( get_include_path () . PATH_SEPARATOR . APPPATH .'application/libraries/google-api-php-client/src/Google' ); require_once APPPATH . "libraries/google-api-php-client/src/Google/autoload.php"; require APPPATH . "libraries/google-api-php-client/src/Google/Client.php"; require APPPATH . "libraries/google-api-php-client/src/Google/Service/Oauth2.php"; //    ,    Google API. $client = new Google_Client (); $client->setApplicationName ( "A3M with OAuth2 support" ); $client->setClientId ( $client_id ); $client->setClientSecret ( $client_secret ); $client->setRedirectUri ( $redirect_uri ); $client->addScope ( "email" ); $client->setOpenidRealm ( $redirect_uri ); //      OpenID 2.0 

That is, if you request openid_realm , we get back openid_id , which CodeIgniter uses as the unique user ID in the database.

By the way, there is one interesting point. If we (on the CodeIgniter site) already have an old user base that logged in with Google, when it still supported OpenID 2.0, then most likely when trying to authenticate through OAuth2 we will get a completely different openid_id and, accordingly, will not be able to identify the user from the database.

In order for open_id to always be the same, it is necessary that the Redirect URI in both cases be identical.
More details can be read here:
stackoverflow.com/a/23051643/524743
stackoverflow.com/q/29229204/524743

Here is the method for getting the client's openid_id :

 // This method extracts openID2 ID form id token for backward compatibility private function getOpenIDFromToken($client, $token) { $id_token = json_decode ( $token ); $ticket = $client->verifyIdToken ( $id_token->{'id_token'} ); if ($ticket) { $data = $ticket->getAttributes (); return $data ['payload'] ['openid_id']; // user ID } return false; } 

Begin the authentication process:

 $objOAuthService = new Google_Service_Oauth2 ( $client ); if (! isset ( $authURL )) //         “Expired Token” unset ( $_SESSION ['access_token'] ); //       //       endpoint if (isset ( $_GET ['code'] )) { $client->authenticate ( $_GET ['code'] ); $_SESSION ['access_token'] = $client->getAccessToken (); header ( 'Location: ' . filter_var ( $redirect_uri, FILTER_SANITIZE_URL ) ); } //    ,  openid_id if (isset ( $_SESSION ['access_token'] ) && $_SESSION ['access_token']) { $client->setAccessToken ( $_SESSION ['access_token'] ); $openid_id = $this->getOpenIDFromToken ( $client, $client->getAccessToken () ); } //           if ($client->getAccessToken ()) { $userData = $objOAuthService->userinfo->get (); $data ['userData'] = $userData; $_SESSION ['access_token'] = $client->getAccessToken (); $openid_id = $this->getOpenIDFromToken ( $client, $client->getAccessToken () ); } //       ,    URI,     . else { $authUrl = $client->createAuthUrl (); $data ['authUrl'] = $authUrl; header ( 'Location:' . $authUrl ); die (); //      :) } 

...
After receiving user data, we check if it is in the database, and if not, create a new record:

 if (! $this->authentication->is_signed_in ()) { if ($userData) { $email = $userData->getEmail (); $openid_google = array('fullname' => $userData->getName (), $openid_google 'gender' => $userData->getGender (), $openid_google 'language' => $userData->getLocale (), $openid_google 'firstname' => $userData->getGivenName (), // google only $openid_google 'lastname' => $userData->getFamilyName (), // google only ); } // Store user's google data in session $this->session->set_userdata ( 'connect_create', array ( array ( 'provider' => 'openid', 'provider_id' => isset ( $openid_id ) ? $openid_id : NULL, 'email' => isset ( $email ) ? $email : NULL ), $openid_google ) ); // Create a3m account redirect ( 'account/connect_create' ); 


Done! User in the database, authentication failed and everyone is happy.

All sources are here . If you have any questions, I will be happy to help.

Source: https://habr.com/ru/post/266339/


All Articles