Authentification via les réseaux sociaux
Introduction
Package d'authentification via les réseaux sociaux pour BowPHP. Il permet à vos
utilisateurs de se connecter avec leurs comptes sociaux existants plutôt que de
créer un mot de passe supplémentaire. En interne, le package s'appuie sur
thephpleague/oauth2-client et
exécute pour vous le flux OAuth 2.0 standard à code d'autorisation :
- Votre application redirige l'utilisateur vers l'écran de consentement du fournisseur.
- L'utilisateur approuve, et le fournisseur rappelle votre application avec un code.
- Le package échange ce code contre un jeton d'accès et retourne
l'utilisateur authentifié sous la forme d'un
UserResource.
La protection CSRF (le paramètre OAuth state) est générée, stockée et vérifiée
pour vous à chaque aller-retour.
Actuellement, il supporte les fournisseurs suivants :
| Fournisseur | Identifiant ($provider) |
|---|---|
facebook | |
| Gitlab | gitlab |
| Github | github |
google | |
instagram | |
linkedin |
Installation
Pour installer ce paquet, vous devez utiliser composer. Nous vous recommandons de l'installer globalement.
composer require bowphp/soauth
Configuration
Après l'installation, dans votre fichier .env.json, vous devez définir les informations d'accès au fournisseur comme suit :
Configuration Facebook
Vous pouvez créer une nouvelle application Facebook à l'adresse https://developers.facebook.com/fr.
{
"FACEBOOK_CLIENT_ID": "client_id",
"FACEBOOK_CLIENT_SECRET": "client_secret",
"FACEBOOK_REDIRECT_URI": "redirect_uri"
}
Configuration Gitlab
{
"GITLAB_CLIENT_ID": "client_id",
"GITLAB_CLIENT_SECRET": "client_secret",
"GITLAB_REDIRECT_URI": "redirect_uri"
}
Configuration GitHub
{
"GITHUB_CLIENT_ID": "client_id",
"GITHUB_CLIENT_SECRET": "client_secret",
"GITHUB_REDIRECT_URI": "redirect_uri"
}
Configuration Google
{
"GOOGLE_CLIENT_ID": "client_id",
"GOOGLE_CLIENT_SECRET": "client_secret",
"GOOGLE_REDIRECT_URI": "redirect_uri"
}
Configuration Instagram
{
"INSTAGRAM_CLIENT_ID": "client_id",
"INSTAGRAM_CLIENT_SECRET": "client_secret",
"INSTAGRAM_REDIRECT_URI": "redirect_uri"
}
Configuration LinkedIn
{
"LINKEDIN_CLIENT_ID": "client_id",
"LINKEDIN_CLIENT_SECRET": "client_secret",
"LINKEDIN_REDIRECT_URI": "redirect_uri"
}
La configuration suit toujours la même approche : trois clés
<PROVIDER>_CLIENT_ID, <PROVIDER>_CLIENT_SECRET,
<PROVIDER>_REDIRECT_URI.
Le redirect_uri que vous définissez ici doit correspondre exactement à la
route de callback que vous enregistrez dans votre application (voir
Ajouter une route) ainsi qu'à celle déclarée dans la
console développeur du fournisseur — sans quoi le fournisseur rejettera la
requête.
Ces valeurs d'environnement sont lues par le fichier config/soauth.php du
package, qui associe chaque nom de fournisseur à ses identifiants. Votre propre
config/soauth.php, s'il existe, est fusionné par-dessus les valeurs par
défaut, ce qui vous permet de surcharger n'importe quelle valeur localement.
Version de l'API Graph de Facebook
Le fournisseur Facebook communique avec une version précise de l'API Graph
(v18.0 par défaut). Pour fixer une autre version, surchargez la clé
graph_api_version dans votre config/soauth.php :
return [
'facebook' => [
'client_id' => app_env('FACEBOOK_CLIENT_ID'),
'client_secret' => app_env('FACEBOOK_CLIENT_SECRET'),
'redirect_uri' => app_env('FACEBOOK_REDIRECT_URI'),
'graph_api_version' => 'v19.0',
],
];
Utilisation
Activez le package en l'ajoutant à Kernel::configurations() :
public function configurations(): array
{
return [
\Bow\Soauth\SoauthConfiguration::class,
// ... autres providers
];
}
Le package expose un unique point d'entrée statique — Bow\Soauth\Soauth —
avec deux méthodes :
Soauth::redirect(string $provider, array $scope = [])— envoie l'utilisateur vers l'écran de consentement du fournisseur.Soauth::resource(string $provider)— gère le callback et retourne l'utilisateur authentifié sous forme deUserResource.
Nous considérons le contrôleur suivant :
namespace App\Controllers;
use App\Controllers\Controller;
use Bow\Soauth\Soauth;
class SoauthController extends Controller
{
/**
* Redirection vers le fournisseur défini
*
* @param string $provider
* @return mixed
*/
public function redirect(string $provider)
{
// Le second argument $scope est optionnel : passez un tableau de
// permissions OAuth (ex. ['email', 'public_profile']) ou omettez-le
// pour utiliser le scope par défaut du fournisseur.
return Soauth::redirect($provider, ['email']);
}
/**
* Gérer le retour du fournisseur OAuth
*
* @param string $provider
* @return mixed
*/
public function handle(string $provider)
{
$user = Soauth::resource($provider);
// Connectez l'utilisateur ou créez-le, puis redirigez :
session()->add('user', $user->toArray());
return redirect('/dashboard');
}
}
La valeur $provider provient de la route et doit correspondre à l'un des
fournisseurs supportés : facebook, gitlab, github, google,
instagram ou linkedin. Un nom inconnu ou non configuré lève une
Bow\Soauth\Exception\SoauthException.
Scopes
Le second argument de Soauth::redirect() est la liste des permissions OAuth
(« scopes ») que vous demandez à l'utilisateur d'accorder. Les scopes sont
propres à chaque fournisseur, alors ne demandez que ce dont vous avez besoin :
// Demander à Facebook l'email et le profil public
return Soauth::redirect('facebook', ['email', 'public_profile']);
// Demander à GitHub les adresses email de l'utilisateur
return Soauth::redirect('github', ['user:email']);
Omettez complètement l'argument pour revenir au scope par défaut du fournisseur :
return Soauth::redirect('google');
Ajouter une route
Définissez les routes qui seront utilisées pour les actions d'appel Soauth :
$app->get('/oauth/:provider/redirect', 'SoauthController::redirect');
$app->get('/oauth/:provider/callback', 'SoauthController::handle');
Le segment :provider devient l'argument $provider passé à vos méthodes de
contrôleur. La route /callback doit correspondre au redirect_uri configuré
pour le fournisseur.
Récupérer l'utilisateur
Soauth::resource() retourne une instance de Bow\Soauth\UserResource. Elle
normalise les données renvoyées par les différents fournisseurs derrière un
ensemble cohérent d'accesseurs, afin que votre code n'ait pas à se ramifier
selon le fournisseur :
$user = Soauth::resource($provider);
$user->getId(); // id utilisateur du fournisseur (string)
$user->getName(); // nom complet
$user->getNickName(); // nom d'utilisateur / pseudo
$user->getFirstName(); // prénom
$user->getLastName(); // nom de famille
$user->getEmail(); // adresse email
$user->getPictureUrl(); // URL de l'avatar (normalisée entre fournisseurs)
$user->getGender(); // genre
$user->getLink(); // URL du profil
$user->getHometown(); // localisation (array)
Chaque accesseur retourne null lorsque le fournisseur n'a pas fourni le champ
(par exemple lorsque le scope correspondant n'a pas été demandé), pensez donc
toujours à vérifier la valeur avant de l'utiliser.
Pour travailler avec la charge utile brute, utilisez toArray() pour obtenir la
réponse complète du fournisseur ou getAttribute() pour lire une seule clé :
$all = $user->toArray(); // tableau normalisé complet
$verified = $user->getAttribute('verified_email'); // toute clé propre au fournisseur
Certains accesseurs de UserResource — getBio(), getCoverPhotoUrl(),
getLocale() et getTimezone() — correspondent à des champs que les
fournisseurs ont dépréciés ou supprimés, et retourneront généralement null.
Préférez les accesseurs activement supportés ci-dessus.
Gestion des erreurs
Le package lève une Bow\Soauth\Exception\SoauthException dans les cas
suivants :
- le nom de
$providerdemandé est inconnu ; - le fournisseur n'est pas configuré (bloc d'identifiants manquant) ;
- le
stateOAuth est manquant, expiré ou ne correspond pas (une tentative CSRF possible, ou l'utilisateur est arrivé sur le callback sans être passé parredirect()au préalable) ; - le code d'autorisation est absent de la requête de callback.
Encapsulez le traitement du callback pour échouer proprement :
use Bow\Soauth\Soauth;
use Bow\Soauth\Exception\SoauthException;
public function handle(string $provider)
{
try {
$user = Soauth::resource($provider);
} catch (SoauthException $e) {
return redirect('/login')->withFlash('error', 'Échec de l\'authentification.');
}
session()->add('user', $user->toArray());
return redirect('/dashboard');
}
Il manque quelque chose ?
Si vous rencontrez des problèmes avec la documentation ou si vous avez des suggestions pour améliorer la documentation ou le projet en général, veuillez déposer une issue pour nous, ou envoyer un tweet mentionnant le compte Twitter @bowframework ou directement sur le github.