Adding authentication to Laravel application is a matter running php artisan make:auth
and the authentication routes and views will be added to you application. The authentication system will fetch the user to be authenticated from the database when using the default authentication scaffold.
In cases where users may not be in the database configured to be used with your application but are fetched from an external API, we can still use the default authentication system to authenticate these users in our application.
To do this, lets try to understand the authentication system of Laravel.
Laravel's authentication facilities are made up of "guards" and "providers".
Guards define how users are authenticated for each request. For example, Laravel ships with a session guard which maintains state using session storage and cookies. There is also a token guard for token based authentication.
Providers define how users are retrieved from your persistent storage. Laravel ships with support for retrieving users using Eloquent and the database query builder.
In our case, we will be using Zendesk as the provider.
Laravel provides the Illuminate\Contracts\Auth\UserProvider
and Illuminate\Contracts\Auth\Authenticatable
contracts.
The implementation of Illuminate\Contracts\Auth\Authenticatable
contract will have methods to fetch the user from Zendesk when email and password are provided.
The implementation of Illuminate\Contracts\Auth\UserProvider
will fetch the user from Zendesk. Therefore the implementation of Illuminate\Contracts\Auth\Authenticatable
will be injected in the implementation of Illuminate\Contracts\Auth\UserProvider
.
In the default authentication, the App\User.php class is an implementation of Illuminate\Contracts\Auth\Authenticatable
contract.
In our case we will modify the App\User.php
file to suit our needs.
We will modify the App\User.php
file and add methods to retrieve the user from Zendesk. The two most important methods are retrieve
and getById
. retrieve
fetches the user from Zendesk and getById
retrieves the user from session using an identifier. There are other methods defined since we are implementing the Illuminate\Contracts\Auth\Authenticatable
contract.
https://github.com/NtimYeboah/laravel-zendesk-authentication/app/User.php
.
.
.
use App\Traits\MakesHttpRequests;
use Illuminate\Contracts\Auth\Authenticatable;
class User extends Authenticatable
{
use MakesHttpRequests;
.
.
.
/**
* Get user from Zendesk
*
* @param array $credentials
*
* @return \App\User
*/
public function retrieve($credentials)
{
$url = 'https://' . config('services.zendesk.subdomain') . '.zendesk.com/api/v2/users/me.json';
$response = $this->get($url, [
'auth' => [
$credentials['email'],
$credentials['password']
]
]);
$user = json_decode((string) $response->getBody())->user;
session()->put('email', (string) $response->getBody());
$this->username = $user->name;
$this->password = $credentials['password'];
return $this;
}
/**
* Retrieve user by identifier
*
* @param string $identifier
*
* @return mixed
*/
public function getById($identifier)
{
return json_decode(session()->get($identifier))->user;
}
.
.
.
}
The implementation of Illuminate\Contracts\Auth\UserProvider
is responsible for fetching the implementation of Illuminate\Contracts\Auth\Authenticatable
from Zendesk. The noticable methods are
-
retrieveById
which delegates the retrieval of the user from the session to the implementation ofIlluminate\Contracts\Auth\Authenticatable
thus the User.php class. -
retrieveByCredentials
which retrieves the user from Zendesk when the email and password are provided. The retrieval of the user is delegated to the User.php class. -
validateCredentials
which validates a user against the provided credentials. In this method, we check the password of the user against the password in the provided credentials.
There are other methods that should be implemented since we are implementing an interface.
https://github.com/NtimYeboah/laravel-zendesk-authentication/app/Extensions/ZendeskUserProvider.php
use Illuminate\Contracts\Auth\UserProvider;
class ZendeskUserProvider implements UserProvider
{
/**
* The user to be authenticated
*
* @var $user
*/
public $user;
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
return $this->user->getById($identifier);
}
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
if (! $credentials) {
return;
}
return $this->user->retrieve($credentials);
}
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials)
{
return $user->password === $credentials['password'];
}
.
.
.
We need to register the authentication provider so that Laravel will be aware and use it for authentication. In the boot
method of the AuthServiceProvider
we will register our authentication provider and guard. We will be using the session guard already included with Laravel. We will register both the provider and guard name as zendesk
.
https://github.com/NtimYeboah/laravel-zendesk-authentication/app/Providers/AuthServiceProvider.phpp
use App\User;
use Illuminate\Auth\SessionGuard;
use App\Extensions\ZendeskUserProvider;
.
.
.
class AuthServiceProvider extends ServiceProvider
{
.
.
.
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::provider('zendesk', function ($app, array $config) {
return new ZendeskUserProvider($app->make(User::class));
});
Auth::extend('zendesk', function ($app, $name, array $config) {
return new SessionGuard('session',
Auth::createUserProvider($config['provider']),
$app->make('session.store'),
$app->make('request'));
});
}
}
Additionally, after registering the provider and guard, lets switch to use them in the authentication configuration file. Modify the config/auth.php
to add the provider and guard.
Under the providers section, add the following
'providers' => [
'users' => [
'driver' => 'zendesk'
]
Under the guard section, append the following provider to the list of guards
'custom' => [
'driver' => 'zendesk',
'provider' => 'users',
],
And then finally, set the default guard to be used for authentication under the defaults
key.
'defaults' => [
'guard' => 'custom',
'passwords' => 'users',
],