In this step we just need to create a new Erdiko project, for more details please refer to Erdiko
composer create erdiko/erdiko oauth_authenticate_sample
The next step is add the additional libraries.
In both cases, inside the project directory, will add new required packages
composer require erdiko/authenticate
composer require league/oauth2-client
composer require league/oauth2-facebook
Once it’s added we will need to add the config file in app/config/default/authenticate.json this is an example:
{ "authentication": { "available_types": [{ "name": "mock", "namespace": "erdiko_authenticate_Services", "classname": "Mock", "enabled": true }] }, "storage": { "selected": "session", "storage_types": [{ "name": "session", "namespace": "erdiko_authenticate_Services", "classname": "SessionStorage", "enabled": true }] } }
we will revisit this file in future sections.
This package doesn’t need a special configuration, but let’s take a look at constructor parameters we will user in our extension.
$provider = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => 'demoapp',
'clientSecret' => 'demopass',
'redirectUri' => 'http://example.com/yourredirecturl/',
'urlAuthorize' => 'http://example.com/oauth2/authorize',
'urlAccessToken' => 'http://example.com/oauth2/token',
'urlResourceOwnerDetails' => 'http://example.com/oauth2/resource'
]);
clientId and clientSecret, come from the dashboard of your registered app, in the picture below are App ID and App Secret.
redirectUri, is a public URL in your server where you will be redirected after oAuth server finish the authentication process (Facebook in our example)
The last three keys (urlAuthorize, urlAccessToken and urlResouceOwnerDetails) will change based on which service we are using. In the above block, we assume that the the oAuth server is placed in example.com, maybe our custom implementation.
We will implements AuthenticationInterface that way we can inject it in our authenticate package thru autenticate.json config file we added previously.
In authentication section you will have to add a new entry in available_types array:
{ "name": "oauth", "namespace": "app_services", "classname": "oAuthAuthenticator", "enabled": true }
In the constructor method of this class we will create a provider instance for the client, but we will use the third package (oauth2-facebook) to simplify things:
namespace app\services;
use erdiko\authenticate\AuthenticationInterface;
use \League\OAuth2\Client\Provider\Facebook;
class oAuthAuthenticator implements AuthenticationInterface
{
protected $provider;
public function __construct()
{
session_start();
$this->provider = new Facebook([
'clientId' => '1925853064368417',
'clientSecret' => '55ea4c1a56ca6d1db485b954ZZZ',
'redirectUri' => 'https://example.com/login/setlogin',
'graphApiVersion' => 'v2.8',
]);
}
public function login($credentials)
{
if(!$this->checkLoggedUser()) {
$authorizationUrl = $this->provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $this->provider->getState();
header('Location: ' . $authorizationUrl);
return;
}
}
protected function checkLoggedUser()
{
return (
isset($_SESSION['code'])
&& isset($_SESSION['oauth2state'])
);
}
public function verify($credentials)
{
return true;
}
}
As you can see in the login method, I’ve added a simplistic check for a logged user, if there’s no record in session will redirect to login popup. Now we’re delegating the authentication process to Facebook, and the result of this process will be finally handled by method getSetLogin in the login controller.
In this example we are using a Login Controller just to keep authentication logic isolated. This is a normal erdiko controller, where we will have three basic actions: getLogin – that will load a basic -authenticator and invoke the login method. This action will be loaded when you click on Login with Facebook buttons that you can find everywhere these days.
public function getLogin()
{
$authenticator = new BasicAuthenticator(new User);
$authenticator->login(array(),'oauth');
}
getSetLogin – a callback method – is responsible to manage Facebook response and storage user in SESSION.
public function getSetLogin()
{
$authenticator = new BasicAuthenticator(new User());
if (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
throw new \Exception('Invalid state.');
}
$token = $this->provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
try{
$user = $this->provider->getResourceOwner($token);
$authenticator->persistUser($user);
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
}
Finally, we have the getLogout action, that will destroy the SESSION and user won’t be longer authenticated.
public function getLogout()
{
$authenticator = new BasicAuthenticator(new User());
$authenticator->logout();
\erdiko\core\helpers\FlashMessages::set("Good bye, ".$authenticator->currentUser()->getUsername(), "success");
$this->getLogin();
}
It’s pretty easy to add oAuth features on your system as you can see. Delegating the authentication process to a trusted server, providing users with the ability to use existing trusted accounts is a clear win.
Hope you enjoy this small example! Thanks for reading and hope to see you in my next post!
Tags: Auth, cloud, oauth, php, programming, web, web services
Categories: Cloud, Miscellaneous, PHP, Programming
Lets talk!
Join our mailing list, we promise not to spam.