Using oAuth2.0 to sign-in with Google using redirect method

No library required

In this example we have the main app (in this case my blogpost) with a Log-in button (Log in Example, above ), that redirects to the Log-In app, which on the other hand redirects to selected Log-In service (Google, Apple, Facebook, Github) passing app id an all necessary log in data.

After the user grant permissions to share requested data (email, username, real name, etc.) called scope, authentication service is calling back our app service, passing code which our service is using to make HTTP request to the provider and exchange it for JWT (Jason Web Token) containing requested user information.

Create Authorization credentials

  • Navigate to https://console.cloud.google.com/apis/credentials  and click on the + CREATE CREDENTIALS on the top left of the page.
  • on Authorized Java Script Origins add the domain from where the WEB app will be served. You could use http://localhost if you like.
  • on Authorized Redirect URIs add authentication service callback script that Google will call to pass code that could be exchanged for JWT (JSON Web Token) containing user’s information requested.

On the top right corner you will see ClientID and App secret. Write them down since we are going to need them in our authentication service later on.

Create main WEB app and authentication service

We will create main WEB app and authentication service that main app will use. This way same authentication service could be used for different WEB aps.

(Main web app) with Log In button, that redirects to the authentication app.

Let’s get started by creating simple WEB app that will have Log In button, that will simply redirect to our log in service. I already did that in the “Log In Example” above.

index.html

<html>
  <head>
    <style>
     ...
    </style>
  </head>

  <body>
    <!-- there is no Java script involved at all -->
    <div id="log_in_wrapper">
      <button class='continue_with_google'>
        <a href='https://log-in-service-app/index.html'>
          Log In
        </a>
      </button>
    </div>
  </body>
</html>

Nothing fancy happens here. We have button that simply redirects to our authentication service, which draws log-in with  buttons (with Google, Apple, Facebook, GitHub)

(Authentication app) that shows log-in with  buttons (with Google, Apple, Facebook, GitHub)

index.php

<html>
  <head>
    <style>
      ...
    </style>
  </head>

  <body>
    <!-- there is no Java script involved at all -->
    <div id="log_in_wrapper">
      <button class='continue_with_google'>
        <a href='step-1-auth-google-get-redirect.php'>
          <img src="some-google-logo"/>
          <span>Continue with Google</span>
        </a>
      </button>
    </div>
  </body>
</html>

This is just another Web app that shows log in buttons. We could skip this step and simply have this buttons in the main WEB app.

For simplicity I only added Log In With google.

This button redirects to step-1-auth-google-get-redirect.php the first part of our authentication service.

 

Creating config file

<?php

// Fill these out with the values you got from Google
$googleClientID = '989056576533-mtef8cl5is5ogjh3np580ireurns7l5k.apps.googleusercontent.com';
$googleClientSecret = 'xxxxxxxxxxxxxx';

// This is the URL we'll send the user to first to get their authorization
$authorizeURL = 'https://accounts.google.com/o/oauth2/v2/auth';

// This is Google's OpenID Connect token endpoint
$tokenURL = 'https://www.googleapis.com/oauth2/v4/token';

// The main application URL. Google will pass JWT token back to the main app
$baseURL = 'https://www.toni-develops.com/external-files/examples/oauth-with-google-with-redirect-step-by-step/step-2-auth-google-redirect.php';

$usserInfoURL = 'https://www.googleapis.com/oauth2/v3/userinfo';

// the initial app url
$initialAppURL = 'https://www.toni-develops.com/2023/01/05/using-oauth2-0-to-log-in-with-google-using-redirect/';

 

After selecting to log-in with desired authentication provider, call backend service to prepare all necessary parameters and call selected authentication service (Google, Apple, Facebook, GitHub)

step-1-auth-google-get-redirect.php

<?php
// add Google app config params
include 'google-config.php';

// Start a session so we have session id to make sure that the redicect is instantiated by this script
$sessionId = '123';

// ####################################################
// STEP 1: Start the login process by sending the user
// to Google's authorization page, 
// and passing app params
// ####################################################


  // Generate a random hash and store in the session to make sure that 
  //$_SESSION['state'] = bin2hex(random_bytes(16));

  $params = array(
    'response_type' => 'code',
    'client_id'     => $googleClientID,
    'redirect_uri'  => $baseURL,
    'scope'         => 'openid email profile',
    'state'         => $sessionId
  );

  // Redirect the user to Google's authorization page, passing the above parameters as a GET request
  header('Location: ' . $authorizeURL . '?' . http_build_query($params));

This simply redirects to the authentication service. In this case Google, passing these parameters:

  • response_type – we requesting code in the response which we are going to exchange it for JWT
  • client_id – is the app id that we registered
  • redirect_url – is our authentication service url, that Google will call passing code parameter. Here we are going to exchange it for JWT In this example this is step-2-auth-google-redirect.php` script below.
  • scope – is the requested scope. In our example we just need user name and email: openid email profile
  • state – this is unique string identifier, that we will check in the callback to make sure that this sign-in workflow is originated by our script

Everything that happens in the above file, could be achieved by simply passing this url in the browser. If you examine the url, it simply passes the same get parameters and query string params.

Next step: Google calls our callback script, passing code which our script exchange for JWT containing user info

step-2-auth-google-redirect.php

<?php
// add Google app config params
include 'google-config.php';

// ####################################################
// Step 2: When Google redirects the user back here, 
// there will be a "code" and "state"
// parameter in the query string
// Exchange the auth code for a JWT token,
// and extract requested user data from there
// ####################################################
if(isset($_GET['code'])) {
  
  // Verify the state matches our stored state
  if(!$_GET['state'] && $_GET['state'] !== '123') {    
    die('missing state!');
  }
  
  // Exchange the auth code for a token
  $ch = curl_init($tokenURL);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'grant_type' => 'authorization_code',
    'client_id' => $googleClientID,
    'client_secret' => $googleClientSecret,
    'redirect_uri' => $baseURL,
    'code' => $_GET['code']
  ]));

  $response = curl_exec($ch);

  // $data will contain 
  // access_token, 
  // expires_in, 
  // scope, 
  // token_type, 
  // id_token - which is JWT token, containing user data according to requested scope from the initial script.
  $data = json_decode($response, true);
  //echo '<pre>';print_r($data);die("</pre>");

  // Note: You'd probably want to use a real JWT library
  // but this will do in a pinch. This is only safe to do
  // because the ID token came from the https connection
  // from Google rather than an untrusted browser redirect

  // Split the JWT string into three parts
  $jwt = explode('.', $data['id_token']);

  // Extract the middle part, base64 decode it, then json_decode it
  $IDToken = json_decode(base64_decode($jwt[1]), true);
  
  // This step is required only if we want to get extra info
  /*
  $ch = curl_init($usserInfoURL);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer '.$data['access_token']
  ]);
  $userInfo = curl_exec($ch);
  */
  /*
  echo '<h1>Token ID</h1>';
  echo '<pre>';print_r($IDToken);echo '</pre>';
  echo '<h1>User info</h1>';
  echo '<pre>';print_r($userInfo);die('</pre>');
  */

  $params = array(
    'email'       => $IDToken['email'],
    'user_name'   => $IDToken['name'],
    'given_name'  => $IDToken['given_name'],
    'family_name'  => $IDToken['family_name']
  );

  // Redirect the user to the initial app passing user data as Query String parameters so the front end could use them.
  header('Location: ' . $initialAppURL . '?' . http_build_query($params));
}
else {
  echo 'Bad response. Missing `code` GET response';
}

line 19-30: we make curl request to Google service passing:

  • grant_type – authorization_code
  • client_id – App id
  • client_secret – App secret
  • redirect_uri – should be url registered in Authorized redirect URLs

  • code – this is the code returned by Google as GET parameter

Last step: We are redirecting back to the main app, passing parameters that front end needs (email, user name) as GET or POST params.

Additionally we could save the user into our database, or do some additional work before redirecting to the main app (line 76)

 

Leave a Reply