Authenticating Users with PHP

This part of the PHP Bookshelf tutorial shows how to create a sign-in flow for users and how to use profile information to provide users with personalized functionality.

By using Google Identity Platform, you can easily access information about your users while ensuring their sign-in credentials are safely managed by Google. OAuth 2.0 makes it easy to provide a sign-in flow for all users of your app and provides your application with access to basic profile information about authenticated users.

This page is part of a multi-page tutorial. To start from the beginning and see instructions for setting up, go to PHP Bookshelf App.

Creating a web application client ID

A web application client ID allows your application to authorize users and access Google APIs on behalf of your users.

  1. Go to the credentials section in the Google Cloud Platform Console.

  2. Click OAuth consent screen. For the product name, enter PHP Bookshelf App. Fill in any relevant optional fields. Click Save.

  3. Click Create credentials > OAuth client ID.

  4. Under Application type, select Web Application.

  5. Under Name, enter PHP Bookshelf Client.

  6. Under Authorized redirect URIs enter the following URLs, one at a time. Replace [YOUR_PROJECT_ID] with your project ID:

    http://localhost:8000/login/callback
    http://[YOUR_PROJECT_ID].appspot.com/login/callback
    https://[YOUR_PROJECT_ID].appspot.com/login/callback
    http://[YOUR_PROJECT_ID].appspot-preview.com/login/callback
    https://[YOUR_PROJECT_ID].appspot-preview.com/login/callback

  7. Click Create.

  8. Copy the client ID and client secret and save them for later use.

Configuring settings

Copy your settings.yml file from the Cloud Storage part of this tutorial to the getting-started-php/4-auth directory. In the copied file, replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with the client ID and client secret you created previously.

Installing dependencies

In the 4-auth directory, enter this command.

composer install

Running the app on your local machine

  1. Start a local web server:

    php -S localhost:8000 -t web
    
  2. In your web browser, enter this address.

    http://localhost:8000

Now you can browse the app's web pages, sign in using your Google account, add books, and see the books you've added using the My Books link in the top navigation bar.

Deploying the app to the App Engine flexible environment

  1. Deploy the sample app:

    gcloud app deploy
    
  2. In your web browser, enter this address. Replace [YOUR_PROJECT_ID] with your project ID:

    https://[YOUR_PROJECT_ID].appspot.com
    

    If you update your app, you can deploy the updated version by entering the same command you used to deploy the app the first time. The new deployment creates a new version of your app and promotes it to the default version. The older versions of your app remain, as do their associated VM instances. Be aware that all of these app versions and VM instances are billable resources.

    You can reduce costs by deleting the non-default versions of your app.

    To delete an app version:

    1. In the GCP Console, go to the App Engine Versions page.

      Go to the Versions page

    2. Click the checkbox next to the non-default app version you want to delete.
    3. Click the Delete button at the top of the page to delete the app version.

    For complete information about cleaning up billable resources, see the Cleaning up section in the final step of this tutorial.

    Application structure

    The following diagram shows the application's components and how they connect to one another.

    Auth sample structure

    Understanding the code

    The PHP session

    This tutorial uses PHP's native session management and memcache to persist a user's session. The PHP runtime is configured by default to use memcache for session configuration. This allows us to use the Silex SessionServiceProvider to manage user data.

    Users will log in with their Google Account, and we will store their basic user data in the session.

    $app->register(new SessionServiceProvider);
    // fall back on PHP's "session.save_handler" for session storage
    $app['session.storage.handler'] = null;
    $app['user'] = function ($app) {
        /** @var Symfony\Component\HttpFoundation\Session\Session $session */
        $session = $app['session'];
    
        return $session->has('user') ? $session->get('user') : null;
    };

    The Google API Client Library for PHP

    The Google API PHP Client provides OAuth functions for users to authenticate using a Google Account. To take advantage of these functions, We need to create the Google\Client service class and configure it for our application.

    $app['google_client'] = function ($app) {
        /** @var Symfony\Component\Routing\Generator\UrlGenerator $urlGen */
        $urlGen = $app['url_generator'];
        $redirectUri = $urlGen->generate('login_callback', [], $urlGen::ABSOLUTE_URL);
        return new Google_Client([
            'client_id'     => $app['config']['google_client_id'],
            'client_secret' => $app['config']['google_client_secret'],
            'redirect_uri'  => $redirectUri,
        ]);
    };

    When the user clicks Log in, the GET '/login' action will use our Google API PHP Client service class to generate the authorization URL and redirect the request.

    $app->get('/login', function () use ($app) {
        /** @var Google_Client $client */
        $client = $app['google_client'];
    
        $scopes = [ \Google_Service_Oauth2::USERINFO_PROFILE ];
        $authUrl = $client->createAuthUrl($scopes);
    
        return $app->redirect($authUrl);
    })->bind('login');

    The redirect_uri we passed to the Google\Client service class is called when the user clicks Allow. This action receives an authorization code, which is used to get an access token. The token data is then stored in the session, and the user is redirected to the home page.

    $app->get('/login/callback', function () use ($app) {
        /** @var Request $request */
        $request = $app['request'];
    
        if (!$code = $request->query->get('code')) {
            return new Response('Code required', Response::HTTP_BAD_REQUEST);
        }
    
        /** @var Google_Client $client */
        $client = $app['google_client'];
        $authResponse = $client->fetchAccessTokenWithAuthCode($code);
    
        if ($client->getAccessToken()) {
            $userInfo = $client->verifyIdToken();
    
            /** @var Symfony\Component\HttpFoundation\Session\Session $session */
            $session = $app['session'];
            $session->set('user', [
                'id'      => $userInfo['sub'],
                'name'    => $userInfo['name'],
                'picture' => $userInfo['picture'],
            ]);
    
            return new Response('', Response::HTTP_FOUND, ['Location' => '/']);
        }
    
        // an error occured while trying to authorize - display it
        return new Response($authResponse['error_description'], 400);
    })->bind('login_callback');

    When the user signs out, the '/logout' action clears the user information from the session.

    $app->get('/logout', function () use ($app) {
        /** @var Symfony\Component\HttpFoundation\Session\Session $session */
        $session = $app['session'];
        $session->remove('user');
    
        return new Response('', Response::HTTP_FOUND, ['Location' => '/']);
    })->bind('logout');

    Useful information about a user, such as their name and picture, are available once a user has authenticated. We can display this information in our base template if they're signed in. If no user information exists, we will display a Login button.

    {% if app.user %}
      {% if app.user.picture %}
        <img src="{{ app.user.picture }}" class="img-circle" width="24" alt="Photo" />
      {% endif %}
      <span>
        {{ app.user.name }} &nbsp;
        <a href="/logout">(logout)</a>
      </span>
    {% else %}
      <a href="/login">Login</a>
    {% endif %}

Send feedback about...