Skip to content

Instantly share code, notes, and snippets.

@emdeeeks
Forked from midorikocak/FacebookAuthenticate.php
Created January 7, 2018 08:34
Show Gist options
  • Save emdeeeks/75139460dae26b683e5a596eafea2756 to your computer and use it in GitHub Desktop.
Save emdeeeks/75139460dae26b683e5a596eafea2756 to your computer and use it in GitHub Desktop.
Facebook Custom Authenticate Object for CakePHP 3.x and Facebook PHP SDK 5.
<?php
namespace App\Auth;
use Cake\Auth\BaseAuthenticate;
use Cake\Network\Request;
use Cake\Network\Response;
use Cake\Core\Configure;
use Cake\Event\Event;
use Cake\Network\Session;
use Facebook;
/**
* Class FacebookAuthenticate
*
* Custom Facebook Authentication Object for Facebook PHP_SDK 5 and for CakePHP 3.x
*
* Insert this file into src/Auth/ folder of your app.
*
* To use a Facebook config file, you should have a facebook.php file in your config folder like
*
* <?php
* return [
* 'Facebook.app_id' => 'YOUR_APP_ID',
* 'Facebook.app_secret' => 'YOUR_APP_SECRET'
* ];
*
* and use Configure::load('facebook', 'default'); in your bootstrap.php.
*
* In your user controller, add $this->Auth->config() into your overridden initialize method:
*
* public function initialize()
* {
* parent::initialize();
* $this->Auth->config('authenticate',
* ['Form',
* 'Facebook' // app authentication object.
* ]);
* }
*
* You also need to have in your composer.json to use this class.
*
* "require": {
* "facebook/php-sdk-v4" : "~5.0",
* "guzzlehttp/guzzle": "^6.1"
* },
*
*
* @link http://book.cakephp.org/3.0/en/controllers/components/authentication.html#creating-custom-authentication-objects
* @link https://developers.facebook.com/docs/php/howto/example_facebook_login
* @package App\Auth
*/
class FacebookAuthenticate extends BaseAuthenticate
{
/**
* @var Facebook\Facebook
*/
private $facebookObject;
/**
* @var Facebook\Helpers\FacebookRedirectLoginHelper
*/
private $helper;
/**
* Constructor
*
* To use Facebook config, you should have a facebook.php in your config folder like
* <?php
* return [
* 'Facebook.app_id' => 'YOUR_APP_ID',
* 'Facebook.app_secret' => 'YOUR_APP_SECRET'
* ];
* and use Configure::load('facebook', 'default'); in your bootstrap.php.
*
* @param \Cake\Controller\ComponentRegistry $registry The Component registry used on this request.
* @param array $config Array of config to use.
*/
public function __construct(\Cake\Controller\ComponentRegistry $registry, array $config = [])
{
parent::__construct($registry, $config);
$this->facebookObject = new Facebook\Facebook([
'app_id' => Configure::read('Facebook.app_id'),
'app_secret' => Configure::read('Facebook.app_secret'),
'default_graph_version' => 'v2.5',
]);
$this->helper = $this->facebookObject->getRedirectLoginHelper();
}
/**
* Implemented Abstract Method for Facebook.
*
* @param Request $request
* @param Response $response
* @return array|bool
*/
public function authenticate(Request $request, Response $response)
{
$accessToken = $this->getAccessToken();
if ($accessToken) {
$user = $this->getFacebookUser($accessToken);
//$accessToken = $this->exchangeAccessToken($accessToken);
$request->session()->write('fb_access_token', (string)$accessToken);
return $user;
} else {
$response->location($this->generateLoginUrl());
}
return false;
}
/**
* TODO: Insert login url into facebook config.
*
* @return string
*/
public function generateLoginUrl()
{
$permissions = ['email', 'user_likes']; // optional
$loginUrl = $this->helper->getLoginUrl('http://' . $_SERVER['SERVER_NAME'] . '/users/login', $permissions);
return $loginUrl;
}
/**
* Changes access token based on example on the link
*
* @link https://developers.facebook.com/docs/php/howto/example_facebook_login
* @param $accessToken
* @return Facebook\Authentication\AccessToken
*/
private function exchangeAccessToken($accessToken)
{
if (!$accessToken->isLongLived()) {
$oAuth2Client = $this->facebookObject->getOAuth2Client();
// Exchanges a short-lived access token for a long-lived one
try {
$accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
} catch (Facebook\Exceptions\FacebookSDKException $e) {
echo "<p>Error getting long-lived access token: " . $this->helper->getMessage() . "</p>\n\n";
exit;
}
}
return $accessToken;
}
/**
* Returns Facebook user array.
*
* @param string $accessToken
* @return array
*/
private function getFacebookUser(string $accessToken)
{
try {
// Returns a `Facebook\FacebookResponse` object
$response = $this->facebookObject->get('/me?fields=id,name,email', $accessToken);
} catch (Facebook\Exceptions\FacebookResponseException $e) {
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch (Facebook\Exceptions\FacebookSDKException $e) {
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
$user = $response->getGraphUser();
return ['facebook' => $user['id'], 'username' => $user['name'], 'email' => $user['email']];
}
/**
* Private method to get Facebook access token. Sometimes returns null.
*
* @return string
*/
private function getAccessToken()
{
try {
$accessToken = $this->helper->getAccessToken();
} catch (Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch (Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
} finally {
return $accessToken;
}
}
/**
* Returns a list of all events that this authenticate class will listen to.
*
* An authenticate class can listen to following events fired by AuthComponent:
*
* - `Auth.afterIdentify` - Fired after a user has been identified using one of
* configured authenticate class. The callback function should have signature
* like `afterIdentify(Event $event, array $user)` when `$user` is the
* identified user record.
*
* - `Auth.logout` - Fired when AuthComponent::logout() is called. The callback
* function should have signature like `logout(Event $event, array $user)`
* where `$user` is the user about to be logged out.
*
* @return array List of events this class listens to. Defaults to `[]`.
*/
public function implementedEvents()
{
return [
'Auth.logout' => 'logout'
];
}
/**
* Logs you out of the app, but does not log you out of Facebook.
* Clever isn't it? :)
*
* @param Event $event
* @param array $user
*/
public function logout(Event $event, array $user)
{
if ($user['facebook']) {
$request = Request::createFromGlobals();
$accessToken = $request->session()->read('fb_access_token');
$this->facebookObject->delete('me/permissions', [], $accessToken);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment