javaabu / efaas-socialite
eFaas Provider for Laravel Socialite
Installs: 1 662
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 3
Forks: 3
Open Issues: 0
Requires
- php: ^7.4 || ^8.0 || ^8.1
- ext-openssl: *
- illuminate/support: ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- laravel/socialite: ^5.15
- lcobucci/clock: ^2.0 || ^3.0
- lcobucci/jwt: ^4.3 || ^5.0
- phpseclib/phpseclib: ^3.0.39
- strobotti/php-jwk: ^1.4
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^4.0 || ^5.0 || ^6.44 || ^7.0 || ^8.0 || ^9.0
- phpunit/phpunit: ^8.5 || ^9.5 || ^10.5
README
Laravel Socialite Provider for eFaas.
Note: Current version of this package is based on eFaas Documentation version 2.2
- eFaas Laravel Socialite
- Requirements
- Installation
- Usage
- Enabling PKCE
- Logging out the eFaas User
- Using eFaas One-tap Login
- Implementing Front Channel Single Sign Out
- Implementing Back Channel Single Sign Out
- Authenticating from mobile apps
- Changing the eFaas login prompt behaviour
- Available Methods for eFaas Provider
- Available Methods and Public Properties for eFaas User
- Changing the eFaas request scopes
- Getting eFaas data from eFaas User object
- Available eFaas data fields
- Testing
- Changelog
- Contributing
- Security
- Credits
- License
Requirements
This package requires the following:
- Laravel 6.0 or higher
- PHP 7.4 or higher
- ext-openssl PHP extension
Installation
For Laravel 6.0+, you can install the package via composer
:
composer require javaabu/efaas-socialite
For Laravel 5.6, use version 1.x
composer require javaabu/efaas-socialite:^1.0
Add configuration to your .env
file
Add the following config to your .env
file
EFAAS_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx EFAAS_CLIENT_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx EFAAS_REDIRECT_URI=https://your-app.com/path/to/efaas/callback EFAAS_MODE=development # for production use #EFAAS_MODE=production
Publishing the config file
Optionally you can also publish the config file to config/efaas.php
:
php artisan vendor:publish --provider="Javaabu\EfaasSocialite\Providers\EfaasSocialiteServiceProvider" --tag="efaas-config"
This is the default content of the config file:
<?php return [ /** * eFaas client config */ 'client' => [ /** * eFaas Client ID */ 'client_id' => env('EFAAS_CLIENT_ID'), /** * eFaas Client Secret */ 'client_secret' => env('EFAAS_CLIENT_SECRET'), /** * eFaas Redirect url */ 'redirect' => env('EFAAS_REDIRECT_URI'), /** * Development mode * supports "production" and "development" */ 'mode' => env('EFAAS_MODE', 'development'), /** * Default scopes for the eFaas client */ 'scopes' => [ 'openid', 'efaas.profile', 'efaas.birthdate', 'efaas.email', 'efaas.mobile', 'efaas.photo', 'efaas.permanent_address', 'efaas.country', 'efaas.passport_number', 'efaas.work_permit_status' ], ], /* * This model will be used to store efaas session sids * The class must implement \Javaabu\EfaasSocialite\Contracts\EfaasSessionContract */ 'session_model' => \Javaabu\EfaasSocialite\Models\EfaasSession::class, /* * This handler will be used to manage saving and destroying efaas session records * The class must implement \Javaabu\EfaasSocialite\Contracts\EfaasSessionHandlerContract */ 'session_handler' => \Javaabu\EfaasSocialite\EfaasSessionHandler::class, /* * This is the name of the table that will be created by the migration and * used by the EfaasSession model shipped with this package. */ 'table_name' => 'efaas_sessions', /* * This is the database connection that will be used by the migration and * the EfaasSession model shipped with this package. In case it's not set * Laravel's database.default will be used instead. */ 'database_connection' => env('EFAAS_SESSIONS_DB_CONNECTION'), ];
Publishing migrations
This package ships with the migrations for an efaas_sessions
table which can be used to implement back channel logout. You can publish these migrations using the following Artisan command:
php artisan vendor:publish --provider="Javaabu\EfaasSocialite\Providers\EfaasSocialiteServiceProvider" --tag="efaas-migrations"
After publishing the migrations, you can run them:
php artisan migrate
Usage
Note: A demo implementation of this package is available here.
You should now be able to use the provider like you would regularly use Socialite (assuming you have the facade installed): Refer to the Official Social Docs for more info.
Warning: If you get 403 Forbidden
error when your Laravel app makes requests to the eFaas authorization endpoints,
request NCIT to whitelist your server IP.
return Socialite::driver('efaas')->redirect();
and in your callback handler, you can access the user data like so. Remember to save the user's id_token
and sid
(session id).
$efaas_user = Socialite::driver('efaas')->user(); $id_token = $efaas_user->id_token; $sid = $efaas_user->sid; session()->put('efaas_id_token', $id_token); session()->put('efaas_sid', $sid);
Enabling PKCE
By default, this package has PKCE disabled. To enable PKCE, use the enablePKCE()
method in both your redirect call and
the callback handler.
return Socialite::driver('efaas')->enablePKCE()->redirect();
// inside callback handler $efaas_user = Socialite::driver('efaas')->enablePKCE()->user();
Logging out the eFaas User
In your Laravel logout redirect, redirect with the provider logOut()
method using the id token saved during login
$id_token = session('id_token'); return Socialite::driver('efaas')->logOut($id_token, $post_logout_redirect_url);
Note: Since the id_token
can be very long, you might run into nginx errors when redirecting. To fix this you can
add the following to your nginx config. More
info here.
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
Using eFaas One-tap Login
This package will automatically add an /efaas-one-tap-login endpoint to your web routes which will redirect to eFaas with the eFaas login code.
Sometimes you may wish to customize the routes defined by the Efaas Provider. To achieve this, you first need to ignore
the routes registered by Efaas Provider by adding EfaasProvider::ignoreRoutes
to the register method of your
application's AppServiceProvider
:
use Javaabu\EfaasSocialite\EfaasProvider; /** * Register any application services. */ public function register(): void { EfaasProvider::ignoreRoutes(); }
Then, you may copy the routes defined by Efaas Provider in its routes file to your application's routes/web.php file and modify them to your liking:
Route::group([ 'as' => 'efaas.', 'namespace' => '\Javaabu\EfaasSocialite\Http\Controllers', ], function () { // Efaas routes... });
Implementing Front Channel Single Sign Out
First, during login, in your efaas callback handler method, save the users sid
(session ID) to your session.
$efaas_user = Socialite::driver('efaas')->user(); $sid = $efaas_user->sid; session()->put('efaas_sid', $sid);
Then, in your single sign out controller handler method, first retrieve the logout token's sid
using the eFaas provider's getLogoutSid()
method. The method will return null
if the provided logout token is invalid. You can then compare the saved sid
in your current session with the retrieved sid
and logout the user if they match.
... public function handleFrontChannelSingleSignOut(Request $request) { $saved_sid = session('efaas_sid'); $request_sid = Socialite::driver('efaas')->getLogoutSid(); if ($request_sid && $saved_sid == $request_sid) { // the logout session matches your saved sid // logout your user here auth()->guard('web')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); } return redirect()->to('/your-redirect-url') } ...
Implementing Back Channel Single Sign Out
For Back Channel Logout, you will need to use Laravel's database
session driver and the provided efaas_sessions
migration.
During login, save the user's sid
(session ID) using the eFaas provider's sessionHandler()
:
$efaas_user = Socialite::driver('efaas')->user(); $sid = $efaas_user->sid; Socialite::driver('efaas') ->sessionHandler() ->saveSid($sid);
Then, in your single sign out controller handler method, first retrieve the logout token's sid
using the eFaas provider's getLogoutSid()
method. The method will return null
if the provided logout token is invalid. You can then use the eFaas provider's sessionHandler()
to logout all laravel sessions that match the sid
.
... public function handleBackChannelSingleSignOut(Request $request) { $sid = Socialite::driver('efaas')->getLogoutSid(); if ($sid) { Socialite::driver('efaas') ->sessionHandler() ->logoutSessions($sid); } // for back channel logout you must return 200 OK response return response()->json([ 'success' => ! empty($request_sid) ]); } ...
Authenticating from mobile apps
To authenticate users from mobile apps, redirect to the eFaas login screen through a Web View on the mobile app.
Then intercept the code
(authorization code) from eFaas after they redirect you back to your website after logging in
to eFaas.
Once your mobile app receives the auth code, send the code to your API endpoint.
You can then get the eFaas user details from your server side using the auth code as follows. Remember to use the stateless()
option as the redirect had originated outside of your server:
$efaas_user = Socialite::driver('efaas')->stateless()->userFromCode($code);
After you receive the eFaas user, you can then issue your own access token or API key according to whatever authentication scheme you use for your API.
Changing the eFaas login prompt behaviour
The eFaas login prompt behaviour can be customized by modifying the prompt option on your redirect request
return Socialite::driver('efaas')->with(['prompt' => 'select_account'])->redirect();
The available prompt options are:
Available Methods for eFaas Provider
$provider = Socialite::driver('efaas'); $provider->parseJWT($token); // Parses a JWT token string into a Lcobucci\JWT\Token $provider->getSidFromToken($token); // Validates a given JWT token and returns the sid from the token $provider->getJwksResponse(false); // Returns the JWKs (JSON Web Keys) response as an array from the eFaas API. Optionally return the response as a json string using the optional boolean argument $provider->getPublicKey('5CDA5CF378397733DD33EFBDA82D0F317DCC1D53RS256'); // Returns the public key from JWKs for the given key id as a PEM key string
Available Methods and Public Properties for eFaas User
$efaas_user->isMaldivian(); // Check if is a Maldivian $efaas_user->getDhivehiName(); // Full name in Dhivehi $efaas_user->getPhotoMimetype(); // Get the mimetype of the user photo $efaas_user->getPhotoExtension(); // Get the file extension of the user photo $efaas_user->getPhotoBase64(); // Get the user photo as a base64 encoded string $efaas_user->getPhotoDataUrl(); // Get the user photo as a data url $efaas_user->savePhoto('photo', './path/to/save'); // Saves the user photo to ./path/to/save/photo.jpg and returns the full file path $efaas_user->getAvatar(); // Alias of getPhotoBase64() $efaas_user->sid; // Session id of the user $efaas_user->id_token; // ID Token of the user $efaas_user->token; // Access token of the user
Changing the eFaas request scopes
By default, this package adds all available scopes to the eFaas redirect. You can modify the default scopes by publishing the package config file and changing the scopes. To customize the scopes on a per request basis, you can override the scopes during the redirect.
return Socialite::driver('efaas')->setScopes(['efaas.openid', 'efaas.profile'])->redirect();
Getting eFaas data from eFaas User object
$id_number = $oauth_user->idnumber;
Available eFaas data fields
Different data is associated with different scopes. By default, all scopes are included, so you should be able to get all the data fields.
Scope: efaas.openid
Scope: efaas.profile
Scope: efaas.email
Scope: efaas.mobile
Scope: efaas.birthdate
Scope: efaas.photo
Scope: efaas.work_permit_status
Scope: efaas.passport_number
Scope: efaas.country
Scope: efaas.permanent_address
Here are the fields of the EfaasAddress
object:
The EfaasAddress
class also has the following methods:
$permanent_address = $efaas_user->permanent_address; $permanent_address->getFormattedAddress(); // Get the address with the ward abbreviation. eg: M. Blue Light $permanent_address->getDhivehiFormattedAddress(); // Get the address in Dhivehi with the ward abbreviation. eg: މ. ބުލޫ ލައިޓް
Testing
You can run the tests with
./vendor/bin/phpunit
Changelog
Please see CHANGELOG for more information what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email info@javaabu.com instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.