Search code examples
phpauthenticationhybridauth

HybridAuth authentication cookie


I've tried to implement HybridAuth into my existing web application which uses a classic email+password registration and login but I still don't understand how I should authenticate users with HybridAuth.

My existing authentication system

In my existing login system, a registered user who wants to log in sends his email and password to the server. If the email and password are correct (I don't store users' passwords in plaintext but the password verification process is irrelevant to this question), the server create a hash of the user's encrypted password and a random key. This hash is stored in a cookie and also used to create an authentication code which contains the hash created before, user's email and IP address all hashed together. The authentication code is stored in the user's session.

When an user who's logged in tries to access the site, the server takes the hash from his cookie, hashes it with his email and IP address and compares it to the authentication code which was stored in the session earlier. If the codes match, user is authenticated, otherwise, the user is redirected to a login page.

New HybridAuth system

So far I've only implemented login via Facebook. When a new user clicks a "Login via Facebook" button, the server executes several scripts, redirects the user to Facebook so that he can authorize my app and also creates a new user record in the database with some information from the user's facebook profile. At this point, the user is registered and logged in.

When this user tries to interact with my app, I have to somehow verify his identity. I use this code:

if ($_SESSION['facebook_connected'] == true) {
        try {
            // try social login
            $config = PUBLIC_ROOT . 'handlers/hybridauth/config.php';
            require_once(PUBLIC_ROOT . 'handlers/hybridauth/Hybrid/Auth.php');
            $hybridauth = new Hybrid_Auth($config);
            $adapter = $hybridauth->authenticate('Facebook');
            /* check if the user is registered
            *
            * ...
            *
            */
            return true;
        } catch (Exception $e) {
            return false;
        }
    }

The user is authenticated when this code returns true.

Every time I send a request to my app using the social authentication, the web browser has to wait about 1-2 seconds before it receives the requested web page/data. When I use the email+password authentication, the web page is server almost instantly.

This makes me think that HybridAuth has to communicate with the Facebook server each time it wants to authenticate the user, which is extremely slow.

My question is: Can HybridAuth create some kind of authentication cookie for an user who logs in via Facebook and securely authenticate him each time he sends a request without having to communicate with Facebook?

Sorry for a long question, I wanted to explain my whole authentication system because maybe the whole idea of it is wrong/insecure/outdated and I have to make some changes in order to use it efficiently with HybridAuth.

Side note: The HybridAuth documentation is terrible.


Solution

  • add this columns to your mysql user table

    CREATE TABLE `users` (
        `id` INT(11) NOT NULL AUTO_INCREMENT,
        `password` VARCHAR(250) NOT NULL,
        `name` VARCHAR(60) NOT NULL,
        `email` VARCHAR(250) NULL DEFAULT NULL,
        `mobile` VARCHAR(50) NULL DEFAULT NULL,
        `active` TINYINT(4) NOT NULL DEFAULT '0',
        `gender` VARCHAR(50) NOT NULL DEFAULT '0',
        `img` TEXT NULL,
        `date_joined` DATE NOT NULL,
        `facebook` INT(11) NOT NULL DEFAULT '0',
        `fidentifier` VARCHAR(500) NULL DEFAULT NULL,
        `fprofileURL` VARCHAR(500) NULL DEFAULT NULL,
        `fphotoURL` VARCHAR(500) NULL DEFAULT NULL,
        `fdisplayName` VARCHAR(500) NULL DEFAULT NULL,
        `ffirstName` VARCHAR(500) NULL DEFAULT NULL,
        `flastName` VARCHAR(500) NULL DEFAULT NULL,
        `fgender` VARCHAR(50) NULL DEFAULT NULL,
        `flanguage` VARCHAR(50) NULL DEFAULT NULL,
        `femailVerified` VARCHAR(500) NULL DEFAULT NULL,
        `fcoverInfoURL` VARCHAR(800) NULL DEFAULT NULL,
        PRIMARY KEY (`id`)
    )
    COLLATE='utf8_general_ci'
    ENGINE=InnoDB
    ;
    

    then create php file facebook.php

          <?php
        include 'sql.php';
               function generateRandomString($length = 10) {
            $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789';
            $charactersLength = strlen($characters);
            $randomString = '';
            for ($i = 0; $i < $length; $i++) {
                $randomString .= $characters[rand(0, $charactersLength - 1)];
            }
            return $randomString;
        }
            $config = array(
              "base_url" => "https://yourdomain.com/handlers/hybridauth/",
              "providers" => array (
                "Facebook" => array (
                  "enabled" => true,
                  "keys"    => array ( "id" => "YOUR_ID", "secret" => "YOUR_SECRET" ),
                  "scope"   => "email,public_profile", 
                  "display" => "page" 
            )));
    
            require_once( "handlers/hybridauth/Hybrid/Auth.php" );
    
             try{
            $hybridauth = new Hybrid_Auth( $config );
    
            $adapter = $hybridauth->authenticate( "Facebook" );
    
              $user_profile = $adapter->getUserProfile();
          }
          catch( Exception $e ){
            $user_profile = "denied" ;
    
          }
    
           if ( $user_profile == "denied"){
                            ?>
                <script>
            window.parent.location.href=("login.php?error=1");
            </script>
            <?php  
    
           }
           else
           {
               $fidentifier= $user_profile->identifier;
               $fprofileURL= $user_profile->profileURL;
               $fphotoURL= $user_profile->photoURL;
               $fdisplayName= $user_profile->displayName;
               $ffirstName= $user_profile->firstName;
               $flastName= $user_profile->lastName;
               $fgender= $user_profile->gender;
               $flanguage= $user_profile->language;
               $femailVerified= $user_profile->emailVerified;
               $fcoverInfoURL= $user_profile->coverInfoURL;
               $femail= $user_profile->email;
                $fphone= $user_profile->phone;
    
    
    
               $sqlc = "SELECT * FROM users WHERE fidentifier='$fidentifier' AND facebook=1"; 
            $rs_result = $conn->query($sqlc);
    
            if ($rs_result->num_rows == 1){
            $row = $rs_result->fetch_assoc();
            $_SESSION["user_id"] = $row["id"];
    
                        ?>
                <script>
            window.parent.location.href=("profile.php");
            </script>
            <?php
           }
           else
           {
                $sqlc1 = "SELECT * FROM users WHERE (email='$femailVerified' OR email='$femail') AND facebook=0"; 
            $rs_result1 = $conn->query($sqlc1);
    
            if ($rs_result1->num_rows ==1){
            $row1 = $rs_result1->fetch_assoc();
        $ssid=$row1["id"];
        $sql4 = "UPDATE users SET 
        fidentifier='$fidentifier',
        fprofileURL='$fprofileURL',
        fdisplayName='$fdisplayName',
        name='$fdisplayName',
        ffirstName='$ffirstName',
        flastName='$flastName',
        fgender='$fgender',
        gender='$fgender',
        email='$femail',
        femailVerified='$femailVerified',
        mobile='$fphone',
        fcoverInfoURL='$fcoverInfoURL',
        img='$fphotoURL',
    
        active=1,
            facebook=1
            WHERE id=$ssid";
        if ($conn->query($sql4) === TRUE) {
                $_SESSION["user_id"] = $row1["id"];
            ?>
                <script>
            window.parent.location.href=("profile.php");
    
            </script>
    
            <?php
    
        } else {
    
         echo "Error: " . $sql4 . "<br>" . $conn->error;
        }
    
           }
           else
           {
    
        $password=generateRandomString();
    
    
         $sqlee = "INSERT INTO users (fidentifier,fprofileURL,fdisplayName,name,ffirstName,flastName,fgender,gender,email,femailVerified,mobile,fcoverInfoURL,img,active,facebook,password,date_joined)
    VALUES ('$fidentifier','$fprofileURL','$fdisplayName','$fdisplayName','$ffirstName','$flastName',
    '$fgender','$fgender','$femail','$femailVerified','$fphone','$fcoverInfoURL','$fphotoURL',1,1,'$password',NOW())";
    
        if ($conn->query($sqlee) === TRUE) {
        $lastid = $conn->insert_id;
        $_SESSION["user_id"] = $lastid;
            ?>
                <script>
            window.parent.location.href=("profile.php");
    
            </script>
    
            <?php
        }
    
        else {
            echo "Error: " . $sql . "<br>" . $conn->error;
        }  
           }
    
           }
    
        }
    
        ?>
    

    then call $_SESSION["user_id"] in your pages like this

    <?php
    if ($_SESSION["user_id"] != ""){$suserid=$_SESSION["user_id"];}else{$suserid="";}
    ?>
    

    and when you need user to login you can use something like this

    <?php
    if  ($suserid !=""){
        //do this like a login user
    }
    if  ($suserid ==""){
        echo "login to site by facebook  <a href='facebook.php' >from here</a>";
    }
    ?>
    

    EDIT :

    don't forget to change : include 'sql.php'; // to your mysql connection page

    "base_url" => "https://yourdomain.com/handlers/hybridauth/", // to your domain hybridauth folder

    "keys" => array ( "id" => "YOUR_ID", "secret" => "YOUR_SECRET" ), // YOUR_ID and YOUR_SECRET