Social Logins in PHP with HybridAuth

Share this article

A trend in many of today’s websites is a feature that allows users to sign in via their social network accounts. A classic example is the SitePoint community where users have the option to use their Facebook, Twitter, Google, Yahoo or GitHub account to log in without having to register an account.

In this tutorial, we will be learning about HybridAuth – a PHP library that takes the pain out of building a social login feature.

HybridAuth acts as an abstract API between your application and the various social APIs and identity providers.

Installation

The recommended way to install HybridAuth is via Composer. We’ll also use Slim as a foundation for our sample app.

{
    "require": {
        "slim/slim": "2.*",
        "hybridauth/hybridauth": "2.3.0"
    }
}

Using HybridAuth for Social Logins

To use HybridAuth, copy the config.php and index.php (HybridAuth Endpoint) files in /vendor/hybridauth/hybridauth/hybridauth to your project’s root folder.

Rename the index.php file to hybrid.php because index.php will be used by Slim framework for our demo application logic.

Populate the config.php file with your application’s (e.g. Facebook, Twitter application) credentials.

For example, If you want users to sign in to your website via Facebook, Google, and Twitter; your config file would look pretty much like this. My application URL is http://slim.local.

return 
	[
	    "base_url"   => "http://slim.local/",
	    "providers"  => [
	        "Google"   => [
	            "enabled" => true,
	            "keys"    => [ "id" => "", "secret" => "" ],
	        ],
	        "Facebook" => [
	            "enabled"        => true,
	            "keys"           => [ "id" => "", "secret" => "" ],
	            "trustForwarded" => false
	        ],
	        "Twitter"  => [
	            "enabled" => true,
	            "keys"    => [ "key" => "", "secret" => "" ]
	        ],
	    ],
	    "debug_mode" => true,
	    "debug_file" => "bug.txt",
	];

Note: The base_url parameter must point to the HybridAuth Endpoint file which is hybrid.php in our case.

See HybridAuth Configuration docs for more information.

Next, require the vendor autoloader and instantiate the class.

require 'vendor/autoload.php';
$hybridauth = new Hybrid_Auth( 'config.php' );

Use the authenticate method to authenticate users with a given provider.

For Facebook:

$adapter = $hybridauth->authenticate( "Facebook" );

For Twitter:

$adapter = $hybridauth->authenticate( "Twitter" );

For Google:

$adapter = $hybridauth->authenticate( "Google" );

The parameter that is passed to authenticate() must match the provider array key in config.php file.

After authentication, use the getUserProfile() method to retrieve the profile data of the user.

$user_profile = $adapter->getUserProfile();

The $user_profile variable will be an object that consists of the returned profile data of the user.

More Social Providers

To add more providers to the existing ones e.g. GitHub, copy the GitHub.php file from vendor/hybridauth/hybridauth/additional-providers/hybridauth-github/Providers to a location in your application (provider directory in our case). Use the provider wrapper to load the file where path is the path to the GitHub file and class the name of its PHP class.

"Github"   => [
    "enabled" => true,
    "keys"    => [
        "id"     => "",
        "secret" => ""
    ],
    "wrapper" => [ "path" => "providers/GitHub.php", "class" => "Hybrid_Providers_GitHub" ]
]

Authenticate the user with GitHub with HybridAuth’s autheniticate() method like so:

$adapter = $hybridauth->authenticate( "Github" );

Social Login Implementation

Normally, every website with a login and registration system uses the user’s email address or username for identifying and logging them into their account. If you intend to implement a social login feature, it is recommended not to use the user’s username or email for authentication.

One reason against this practice is that Twitter, for example, does not return the email address of a user authenticated by them. That is, the profile data returned does not contain the user’s email.

Most (if not all) social providers such as Facebook, Twitter, Google, LinkedIn and even GitHub include a unique user identification number returned after authorization.

Instead of using the user’s email for logging them into their account, use the identifier returned by the social providers as follows: create a user account if the user doesn’t have an account or log the user in to the site if he has an account.

Coding a Demo Application

We will be building a simple web application using the Slim PHP framework to demonstrate a real-world example of how social login with HybridAuth could be implemented.

I assume you have HybridAuth and Slim framework installed. If otherwise, see the installation guide above.

Application structure

|-scr/
|----App_Model.php
|-templates/
|----login.php
|----welcome.php
|-vendor/
|-composer.json
|-config.php
|-hybrid.php
|-index.php
|-.htaccess

Here is the SQL for the database table.

CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) NOT NULL AUTO_INCREMENT,
PRIMARY KEY  (id),
  `identifier` varchar(50) NOT NULL,
UNIQUE KEY `identifier` (`identifier`),
  `email` varchar(50) DEFAULT NULL,
  `first_name` varchar(20) DEFAULT NULL,
  `last_name` varchar(20) DEFAULT NULL,
  `avatar_url` varchar(255)
) ENGINE=InnoDB;

Coding the Application Model

All code for the application model should go into the App_Model.php file in src folder.

The file is namespaced Model followed by the class definition and constructor.

<?php
namespace Model;

class App_Model
{

    /** @var object Database connection */
    private $conn;

    /**
     * Instantiate the model class.
     *
     * @param object $db_connection DB connection
     */
    public function __construct(\PDO $db_connection)
    {
        $this->conn = $db_connection;
    }

The identifier_exists method returns true if an identifier (user identification number) already exists in the database or false otherwise.

/**
     * Check if a HybridAuth identifier already exists in DB
     *
     * @param int $identifier
     *
     * @return bool
     */
    public function identifier_exists($identifier)
    {
        try {
            $sql    = 'SELECT identifier FROM users';
            $query  = $this->conn->query($sql);
            $result = $query->fetchAll(\PDO::FETCH_COLUMN, 0);

            return in_array($identifier, $result);
        } catch ( \PDOException $e ) {
            die( $e->getMessage() );
        }

    }

The method register_user inserts the user profile data into the database.

/**
     * Save users record to the database.
     *
     * @param string $identifier user's unique identifier
     * @param string $email
     * @param string $first_name
     * @param string $last_name
     * @param string $avatar_url
     *
     * @return bool
     */
    public function register_user( $identifier, $email, $first_name, $last_name, $avatar_url )
    {
        try {
            $sql = "INSERT INTO users (identifier, email, first_name, last_name, avatar_url) VALUES (:identifier, :email, :first_name, :last_name, :avatar_url)";

            $query = $this->conn->prepare($sql);
            $query->bindValue(':identifier', $identifier);
            $query->bindValue(':email', $email);
            $query->bindValue(':first_name', $first_name);
            $query->bindValue(':last_name', $last_name);
            $query->bindValue(':avatar_url', $avatar_url);

            return $query->execute();
        } catch (\PDOException $e) {
            return $e->getMessage();
        }

    }

The login_user method when called, adds the created user session to a HybridAuth session (created on successful authorization of a user by a provider).

/**
     * Create user login session
     *
     * @param int $identifier
     */
    public function login_user($identifier)
    {
        \Hybrid_Auth::storage()->set('user', $identifier);
    }

The logout_user method removes or destroys the user’s session when the logout link is clicked.

/** Destroy user login session */
    public function logout_user()
    {
        \Hybrid_Auth::storage()->set( 'user', null );
    }

Finally, the getter methods return the user’’s first name, last name, email and avatar URL.

/**
     * Return user's first name.
     *
     * @param int $identifier
     *
     * @return string
     */
    public function getFirstName( $identifier )
    {
        if ( ! isset( $identifier )) {
            return;
        }
        $query = $this->conn->prepare( "SELECT first_name FROM users WHERE identifier = :identifier" );
        $query->bindParam( ':identifier', $identifier );
        $query->execute();
        $result = $query->fetch( \PDO::FETCH_NUM );

        return $result[0];
    }


    /**
     * Return user's last name.
     *
     * @param int $identifier
     *
     * @return string
     */
    public function getLastName( $identifier )
    {
        if ( ! isset( $identifier )) {
            return;
        }
        $query = $this->conn->prepare( "SELECT last_name FROM users WHERE identifier = :identifier" );
        $query->bindParam( ':identifier', $identifier );
        $query->execute();
        $result = $query->fetch( \PDO::FETCH_NUM );

        return $result[0];
    }

    /**
     * Return user's email address
     *
     * @param int $identifier
     *
     * @return string
     */
    public function getEmail( $identifier )
    {
        if ( ! isset( $identifier )) {
            return;
        }
        $query = $this->conn->prepare( "SELECT email FROM users WHERE identifier = :identifier" );
        $query->bindParam( ':identifier', $identifier );
        $query->execute();
        $result = $query->fetch( \PDO::FETCH_NUM );

        return $result[0];
    }


    /**
     * Return the URL of user's avatar
     *
     * @param int $identifier
     *
     * @return string
     */
    public function getAvatarUrl( $identifier )
    {
        if ( ! isset( $identifier )) {
            return;
        }
        $query = $this->conn->prepare( "SELECT avatar_url FROM users WHERE identifier = :identifier" );
        $query->bindParam( ':identifier', $identifier );
        $query->execute();
        $result = $query->fetch( \PDO::FETCH_NUM );

        return $result[0];
    }

Register a PSR-4 autoloader for the Model class by adding the code below to your composer.json file.

"autoload": {
        "psr-4": {"Model\\": "src/"}
    }

Run composer dump-autoload to re-generate the vendor/autoload.php file.

The Application Logic

Require the composer autoload file and instantiate Slim in the application index.php file.

require 'vendor/autoload.php';

$app = new \Slim\Slim();

A directory called templates to store all our template files is created and then registered or configured in Slim as follows:

$app->config(
    [
        'templates.path' => 'templates'
    ]
);

Create a Slim database singleton resource that will return the database connection instance when called.

// Set singleton value
$app->container->singleton( 'db', function () {
        try {
            $db = new PDO( 'mysql:host=localhost;dbname=hybridauth', 'slim', 'slim',
                [ \PDO::ATTR_PERSISTENT => false ] );
        } catch ( PDOException $e ) {
            die( 'Error!: ' . $e->getMessage() );
        }

        return $db;
    }
);

Another singleton resource that returns an instance of HybridAuth is also created.

$app->container->singleton( 'hybridInstance', function () {
    $instance = new Hybrid_Auth('config.php');

    return $instance;
} );

Instantiate the application model class by passing the database connection as a parameter.

$model = new \Model\App_Model( $app->db );

The authenticate function below when added as a parameter to a route, redirects users to the login page if they aren’t logged in.

$authenticate = function ( $app ) {
    return function () use ( $app ) {
        $app->hybridInstance;
        $session_identifier = Hybrid_Auth::storage()->get( 'user' );

        if (is_null( $session_identifier ) && $app->request()->getPathInfo() != '/login/') {
            $app->redirect( '/login/' );
        }
    };
};

Redirect all logged out users to the login page when they visit the application home or index page.

$app->get( '/', $authenticate($app) );

Below is the route definition of the social login links. I.e. when the link http://slim.local/login/facebook is clicked, the user is redirected to Facebook by HybridAuth for authorization. Same goes for Twitter http://slim.local/login/twitter, Google http://slim.local/login/google and every other supported provider.

$app->get( '/login/:idp', function ( $idp ) use ( $app, $model ) {
        try {
            $adapter      = $app->hybridInstance->authenticate( ucwords( $idp ) );
            $user_profile = $adapter->getUserProfile();

            if (empty( $user_profile )) {
                $app->redirect( '/login/?err=1' );
            }

            $identifier = $user_profile->identifier;

            if ($model->identifier_exists( $identifier )) {
                $model->login_user( $identifier );
                $app->redirect( '/welcome/' );
            } else {
                $register = $model->register_user(
                    $identifier,
                    $user_profile->email,
                    $user_profile->firstName,
                    $user_profile->lastName,
                    $user_profile->photoURL
                );

                if ($register) {
                    $model->login_user( $identifier );
                    $app->redirect( '/welcome/' );
                }

            }

        } catch ( Exception $e ) {
            echo $e->getMessage();
        }
    }
);

The HybridAuth authenticate() method is called to redirect the user to the given social provider.

On successful authorization, the variable $user_profile is populated with the user profile data.

The identifier_exists() method is called to check if the user identifier exists in the database. If true, the user is logged in to the site. Otherwise, an account is created for the user and afterward, the user is logged in.

Here is the code for the logout route.

$app->get( '/logout/', function () use ( $app, $model ) {
        $app->hybridInstance;
        $model->logout_user();
        Hybrid_Auth::logoutAllProviders();
        $app->redirect( '/login/' );
    }
);

The logout_user method we talked about in the model class is called to destroy the user session and Hybrid_Auth::logoutAllProviders() is also called to log the user out of the connected provider.

The route for the welcome page where users are redirected to when they log in:

$app->get( '/welcome/', $authenticate( $app ), function () use ( $app, $model ) {
		$app->render( 'welcome.php', [ 'model' => $model ] );
	}
);

Finally, run the Slim application.

// app/index.php
$app->run();

See the application’s GitHub repo for the full source code.

Conclusion

In this article, we learned how to integrate a social login feature with a website using the powerful and robust HybridAuth PHP library.

If you have any questions or contributions, let us know in the comments.

Frequently Asked Questions (FAQs) about Social Logins with PHP and HybridAuth

What is HybridAuth and how does it work with PHP for social logins?

HybridAuth is a popular open-source social sign-on PHP library. It allows web developers to easily build social applications by providing a simple way to authenticate users via their social media accounts. HybridAuth acts as an abstract API between your application and various social APIs and identities providers such as Facebook, Twitter, and Google. It works by integrating with the existing login system in your PHP application and adding social login functionality.

How do I install and configure HybridAuth in my PHP application?

HybridAuth can be installed via Composer, a tool for dependency management in PHP. Once installed, you need to configure it by setting up the providers (social networks) you want to use. Each provider requires a unique set of parameters like keys and secrets which you can get by creating an app on the respective social network’s developer platform.

How secure is HybridAuth for social logins?

HybridAuth is quite secure as it uses OAuth, an open standard for access delegation. OAuth provides secure designated access, meaning users can grant websites access to their information on other websites but without giving them the passwords. This makes HybridAuth a secure choice for implementing social logins.

Can I use HybridAuth for social logins on multiple websites?

Yes, HybridAuth can be used across multiple websites. You just need to configure the library with the correct callback URLs for each website. This makes it a flexible solution for developers managing multiple websites.

How do I handle errors in HybridAuth?

HybridAuth has a built-in error handling system. When an error occurs, it throws an exception which you can catch and handle according to your application’s error handling strategy. This makes it easier to debug and fix issues.

Can I customize the look and feel of the social login buttons with HybridAuth?

Yes, you can customize the look and feel of the social login buttons. HybridAuth provides the functionality for social logins, but the design and layout of the buttons are entirely up to you.

How do I update the HybridAuth library in my PHP application?

Updating HybridAuth is as simple as running a command in Composer. This ensures you always have the latest version with all the security patches and updates.

Can I use HybridAuth with other PHP frameworks?

Yes, HybridAuth is framework-agnostic and can be used with any PHP framework. This makes it a versatile choice for developers working with different PHP frameworks.

How do I test social logins with HybridAuth in a local development environment?

Testing social logins locally can be tricky because social networks require a valid callback URL. However, you can use tools like ngrok to expose your local server to the internet and use that URL as the callback URL.

Can I use HybridAuth to authenticate users via non-social accounts like email and password?

No, HybridAuth is specifically designed for social logins. For traditional email and password authentication, you would need to use other PHP libraries or build your own authentication system.

Collins AgbonghamaCollins Agbonghama
View Author

Collins is a web developer and freelance writer. Creator of the popular ProfilePress and MailOptin WordPress plugins. When not wrangling with code, you can find him writing at his personal blog or on Twitter.

authenticationBrunoShybridauthoauthoauth2OOPHPPHPsocial login
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week