Vous souhaitez nous soutenir ? Devenez sponsor de l'association sur notre page Github

Authentifier vos bots avec laravel/passport

Publié le 6 juillet 2025 par Antoine Benevaut
Couverture de l'article Authentifier vos bots avec laravel/passport

L'authentification est une étape cruciale dans le développement d'une API sécurisée. Elle garantit que seuls les utilisateurs ou systèmes autorisés peuvent accéder aux ressources protégées. En utilisant OAuth2, nous bénéficions d'un standard largement adopté pour gérer les accès et les permissions, tout en offrant une flexibilité pour différents cas d'utilisation.

Les différentes méthodes d'authentification OAuth2 permettent de répondre à des besoins et des circonstances variées telles que l'authentification depuis des applications sur des domaines distincts, l'authentification pour des applications frontend uniquement, comme les applications monopages (Single Page Application) ou mobiles ou encore des applications sans interface de saisie, comme les téléviseurs, qui nécessitent un appareil tiers pour l'authentification.

Et ces méthodes d'authentification ne se limitent pas aux humains, dans cet article nous mettrons en place le flow OAuth2 Client Credentials Grant avec laravel/passport. Ce flow permet l'authentification machine-à-machine (machine-to-machine ou encore M2M), que nous allons utiliser pour identifier le script d'un bot.

Passons à l'action !

Pour une question de simplicité, ce tutoriel ne portera que sur laravel/passport (v12.4.2). J'invite les utilisateurs de laravel/sanctum à consulter la documentation officielle pour mettre en place la cohabitation des deux systèmes d'authentification. Cela peut concerner les utilisateurs de Laravel 10.x et 11.x, qui embarquait par défaut la configuration de laravel/sanctum. Dans ce tutoriel, nous allons utiliser une installation fraiche de laravel 12.x et sans laravel/sanctum donc.

Installation de laravel/passport

On commence par installer le package laravel/passport via composer composer require laravel/passport puis on va initialiser le package avec la commande php artisan passport:install.

Cette commande va générer les clés, les fichiers de configurations et de migrations nécessaires pour l'authentification et créer les clients OAuth par défaut.

La commande php artisan passport:install cumule plusieurs actions, que vous pouvez jouer manuellement si vous le souhaitez :

1php artisan passport:keys
2php artisan vendor:publish --tag passport-config
3php artisan vendor:publish --tag passport-migrations
4php artisan migrate
5php artisan passport:client --personal --name "Nom de votre application - Personal Access client"
6php artisan passport:client --password --name "Nom de votre application - Personal Grant client" --provider "users"

Parmi celles-ci deux sont très importantes et doivent rejoindre la documentation de votre application.

php artisan passport:keys va générer les clés publiques et privées nécessaires pour l'authentification OAuth2 dans le repertoire storage/ avec les noms oauth-private.key et oauth-public.key.

Ces clés sont utilisées pour signer les tokens d'accès. Il vous sera nécessaire de générer ces clés pour chaque environnement où votre application sera déployée.

Vous devrez également les stocker dans un endroit sécurisé, comme un coffre-fort de secrets ou un gestionnaire de clés. Ou encore dans votre fichier .env encrypté, car ces clés peuvent être utilisées depuis les variables d'environnement de votre application PASSPORT_PRIVATE_KEY et PASSPORT_PUBLIC_KEY, cela peut également être pratique pour vos environnements cloud.

php artisan passport:client permet de créer des clients OAuth2 pour vos applications, ce qui vous génère un couple de clef à utiliser avec une méthode spécifique d'authentification OAuth2.

Vous souhaitez authentifier vos utilisateurs en OAuth2 ? Vous devrez créer un client "Authorization Code Grant". Vous voulez authentifier un bot ? Vous devrez créer un client "Client Credentials Grant". Et ainsi de suite en fonction du standard OAuth à utiliser.

Lors de l'installation, la commande crée deux clients par défaut, un client Personal Access Client, utilisé pour générer des tokens personnels côté backend pour les utilisateurs authentifiés.

Et un client Password Grant Client, celui-ci permet généralement d'authentifier des applications mobiles mais, est aujourd'hui obsolète et remplacé par Device Authorization Grant (ce client n'est plus installé dans la version 13.x de laravel/passport, mais j'ai une erreur sur la commande php artisan passport:install au moment de l'écriture de l'article).

Lors de l'exécution de la commande php artisan passport:install, vous remarquerez qu'elle est interactive, prenez garde à ne pas re-installer les migrations si vous la jouez plusieurs fois 😉

A la fin de l'exécution, la sortie console vous indiquera vos identifiants pour vos clients "Personal Access Client" et "Password Grant Client" nouvellement créés.

1Would you like to create the "personal access" and "password grant" clients? (yes/no) [yes]:
2> yes
3 
4 INFO Personal access client created successfully.
5 
6 Client ID ........................................................................................ 1
7 Client secret ............................................. UvPmL0890xqKc4Sp15FMpE3rai5xD1Z5VqrbhntR
8 
9 INFO Password grant client created successfully.
10 
11 Client ID ........................................................................................ 2
12 Client secret ............................................. Zp9FvDIGtoB97bM6XBzERspJ24IXJTmaGKORH3jg

On s'est dit plus haut, que tout ce qui est "Password Grant Client" c'est obsolète, on s'en occupe pas plus que pour l'illustration complète dans l'article.

Par contre, vous devez ranger précieusement vos identifiants pour le client "Personal Access Client" et, en plus de les ajouter à votre coffre-fort numérique, vous allez les placer dans votre fichier d'environnement (.env) avec les clefs ci-dessous :

1PASSPORT_PERSONAL_ACCESS_CLIENT_ID=1
2PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=UvPmL0890xqKc4Sp15FMpE3rai5xD1Z5VqrbhntR

Renseigner ces clefs dans votre fichier .env vous permettra de générer des jetons d'accès (access token), sans cela rien ne fonctionnera ⚠️

À partir d'ici, laravel/passport est prêt pour fonctionner sans plus de configuration ou mise en place. L'installation du package et la configuration que nous venons de réaliser suffit à exposer et rendre exploitable les routes de laravel/passport qui sont préfixées par /oauth/.

La commande php artisan route:list vous permettra de consulter la liste complète. Pas besoin de toutes les retenir, ces routes sont à consommer au besoin, en fonction de vos flows d'authentifications.

Notre première application cliente

Notre application d'authentification est prête et nous souhaitons l'utiliser pour authentifier des applications clientes.

Si cela n'est pas encore clair pour vous, une application cliente peut faire partie du même projet que l'application d'authentification ou être un projet distinct.

Dans les deux cas, nous allons nous connecter à une ou plusieurs routes /oauth/xxx qui nous permettrons de complèter le processus d'authentification jusqu'à obtenir un jeton d'accès.

Lorsque nous allons consommer ces routes, nous allons devoir passer en paramètre des informations relatives au client, ces identifiants, mais aussi des informations relatives à la méthode d'authentification que nous souhaitons réaliser.

Dans notre cas, nous souhaitons connecter un bot, un script simple dans une commande Laravel, pour obtenir un accès à une route protégée.

À partir de ce besoin, il suffit d'explorer la documentation OAuth2 ou Laravel passport pour déterminer la méthode d'authentification à utiliser.

Sans surprise ici, nous allons utiliser le flow "Client Credentials Grant" pour authentifier notre bot, il nous faut donc créer un client adéquat et obtenir ses identifiants.

Il faut alors jouer php artisan passport:client --client dans notre terminal pour obtenir les identifiants pour notre bot. La commande est interactive, vous allez pouvoir donner un nom à votre client puis récupérer vos identifiants qui n'apparaitront qu'une fois ici, mémorisez-les biens.

1What should we name the client? [Laravel ClientCredentials Grant Client]:
2> cat-auth-strophe
3 
4 INFO New client created successfully.
5 
6 Client ID .................................................................................. 4
7 Client secret ....................................... iZDKPOd39otr5qbRDCefsOac3yAhH6xKYMoL2Kac

Pour récupérer notre jeton d'accès, le flow "Client Credentials Grant" est assez simple.

Il vous faudra faire une requête POST à l'URI /oauth/token. À cette requête, on va ajouter deux headers, Content-Type=application/x-www-form-urlencoded (illustré par asForm()) et Authorization=Basic <votre token> (illustré par withToken()) ou <votre token> est une chaine en base64 de la concatenation de vos identifiants.

Enfin, on ajoutera les paramètres grant_type qui est le type de flow utilisé qui correspond directement au flow "Client Credentials Grant". client_id et client_secret nos identifiants.

Pour finir scope qui sera une suite de permissions auxquels notre client prétend lors de l'authentification (cette notion ne sera pas développée dans cet article), ici, la valeur '*' (wildcard) veut dire "toutes les permissions".

1<?php
2 
3$clientId = '4';
4$clientSecret = 'iZDKPOd39otr5qbRDCefsOac3yAhH6xKYMoL2Kac';
5 
6$basicToken = base64_encode("{$clientId}:{$clientSecret}");
7$authenticateClient = \Illuminate\Support\Facades\Http::asForm()
8 ->withToken($basicToken, 'Basic')
9 ->post('http://localhost:8080/oauth/token', [
10 'grant_type' => 'client_credentials',
11 'client_id' => $clientId,
12 'client_secret' => $clientSecret,
13 'scope' => '*',
14 ])
15 ->json()
16;
17 
18dump($authenticateClient);

Si tout s'est bien passé, nous obtenons notre jeton d'accès et un timestamp qui est sa date d'expiration de validité, après quoi il faudra en générer un autre.

1array:3 [
2 "token_type" => "Bearer"
3 "expires_in" => 31536000
4 "access_token" => "eyJ0eXAiOiJKV1QiLCJhb..."
5]

Nous sommes identifié ! Enfin notre bot, il peut maintenant demander des resources auxquels seuls les clients authentifiés peuvent avoir accès.

Que protégeons-nous ?

Parmi les différents flows OAuth2, le flow "Client Credentials Grant" a la particularité d'authentifier le client comme l'entité authentifiée et non pas comme un utilisateur connecté.

Le client sera donc directement l'acteur des différentes requêtes faites aux resources d'API, nous allons ainsi protéger nos resources API en vérifiant que les demandeurs sont bien des clients oauth2.

Pour ce faire, il suffira d'ajouter le middleware CheckClientCredentials::class à vos routes, ainsi seul les clients "Client Credentials Grant" pourront avoir accès à ces routes.

Par la suite, la route protégée peut retourner tout ce que vous souhaitez comme n'importe quel autre controller dont vous avez l'habitude.

Pour illustrer ici, je vous partage comment récupérer l'ID du client qui est en train de faire la requête du côté API. Cela pourrait vous servir pour intégrer cet ID dans vos logs par exemple. Cette information est disponible en retraçant l'identité du client qui effectue la requête via son jeton d'accès.

1use Illuminate\Support\Facades\Route;
2use Illuminate\Http\Request;
3use Lcobucci\JWT\Encoding\JoseEncoder;
4use Lcobucci\JWT\Token\Parser;
5use Laravel\Passport\Token;
6use Laravel\Passport\Http\Middleware\CheckClientCredentials;
7 
8Route::middleware(CheckClientCredentials::class)
9 ->get('/client', function (Request $request) {
10 
11 $tokenId = (new Parser(new JoseEncoder()))
12 ->parse($request->bearerToken())
13 ->claims()
14 ->get('jti');
15 
16 $clientId = Token::find($tokenId)->client_id;
17 
18 return [
19 $clientId,
20 $tokenId,
21 ];
22 });

Notre bot peut maintenant interroger la route /client à laquelle seule les clients "Client Credentials Grant" authentifiés peuvent avoir accès.

Pour l'interroger, on fait une nouvelle requête GET à l'URI /client.

On ajoute notre jeton d'accès via le header Authorization=Bearer <votre token> ou <votre token> est votre jeton d'accès cette fois-ci, remarquez aussi que nous sommes passés à un type d'authentification "Bearer" et plus "Basic".

1<?php
2 
3$clientInformation = \Illuminate\Support\Facades\Http::acceptJson()
4 ->contentType('application/json')
5 ->withToken($authenticateClient['access_token'], 'Bearer')
6 ->get("http://localhost:8080/client")
7 ->json()
8;
9 
10dump($clientInformation);

Une fois la requête jouée, on peut alors récupérer notre ID client et l'ID de son token en cours d'utilisation.

Projetez-vous directement avec vos propres données, nous ne ferons rien de cette information, elles illustrent uniquement le propos de l'article.

1array:2 [
2 0 => 4
3 1 => "91e8829ccba5d0d6f7..."
4]

Notre bot est authentifié et a accès à des données protégées par cette authentification !

Vous avez toutes les cartes en mains pour construire des API sécurisés avec un système d'authentification unifié.

D'autres configurations et fonctionnalités sont encore à découvrir dans ce package.

Plusieurs autres flows d'authentification, comme le Authorization Code Grant certainement le flow d'authentification le plus connu, mais si vous savez "Se connecter avec <réseau social>", nous l'utilisons tous.

Ce flow vous permettra d'authentifier des utilisateurs connectés au travers de client(s) OAuth2, pouvant provenir de plusieurs applications distinctes, mais ne sollicitant qu'une seule base utilisateur et une seule application d'authentification.

Antoine Benevaut avatar
Antoine Benevaut
PHP & Laravel Consultant - Lead Developer, Paris / Passionate / Cat lover / #laravel 😍

A lire

Autres articles de la même catégorie