Lexik vous présente aujourd’hui LexikJWTAuthenticationBundle, destiné à vous aider à mettre en place rapidement un système d’authentification entre votre API REST Symfony2 et d’éventuels clients Javascript (AngularJS, Ember.js, Backbone.js) ou mobiles.
Contexte
Les bonnes ressources concernant la mise en place d’une API REST Symfony2 ne manquent pas :
- les incontournables bundles FOSRestBundle, JMSSerializerBundle, NelmioApiDocBundle
- et de nombreux articles comme ceux de Xavier Lacot, celui de William Durand ou celui de Giulio De Donato entre autres
Mais peu d’informations claires sont disponibles sur l’authentification auprès d’une telle API. Et les stratégies dans ce domaine ne manquant pas, il va falloir faire un choix… Et chez Lexik on a choisit le petit standard qui monte : le Json Web Token (JWT).
Pourquoi JWT ?
Les arguments en faveur de cette méthode sont nombreux : stateless, cross-domain, SPA et mobile ready, standardisé, testé et approuvé par une large communauté notamment AngularJS.
De plus, des projets PHP existent déjà pour nous faciliter le travail, notamment l’excellente libraire namshi/jose dont nous allons nous servir.
Bref, revenons au sujet de l’article ! Après l’avoir testé et mis en place sur plusieurs projets, nous sortons donc aujourd’hui le LexikJWTAuthenticationBundle.
Installation et configuration
Voir la marche à suivre indiquée dans le README du projet github.
Exemple d’utilisation avec AngularJS
Voir l’excellent post sur le blog de Auth0.
Test
Un projet sandbox est aussi disponible pour vous permettre de tester rapidement le système.
Aucun commentaire
Hi. this is **exactly** what I need – but could not get it to work.
1. using the code to generate the keys as you suggested, i got this whenever I logged in:
Warning: openssl_sign(): supplied key param cannot be coerced into a private key
The resultant token was missing the final part so nothing worked from then on.
2. So I generated the keys differently:
openssl genrsa -out app/var/jwt/private.pem 4096
this then permitted login and produced a correctly formatted token
3. However, could not get authentication to work. When I passed the token as a header, it was ignored completely (Authorization: Bearer ), when I passed it in the querystring it was picked up and processed, but always failed verify() in RSA.php – i checked and it was correctly loading the public key resource.
Any tips?
Thanks
Chris
Hi. Further work showed the problem – if you are using a querystring at least (not sure about the headers). The passed token has escaped slashes, so if you pass that token back again it needs to be unescaped (eg stripslashes)
Bonjour Chris,
J’ai eu exactement les mêmes problèmes que toi.
Le premier je l’ai résolu en mettant :
private_key_path: %kernel.root_dir%/var/jwt/private.pem
public_key_path: %kernel.root_dir%/var/jwt/public.pem
Au début j’avais mis : app/var/jwt/public.pem
Par contre je n’arrive toujours pas à m’authentifier via Authorization.
Est-ce qu’il serait possible d’avoir un exemple de code côté front ?
J’ai essayé avec jquery beforeSend (xhr.setRequestHeader) :
Authorization : login:password
Authorization : Basic login:password
Authorization : Basic base64(login:password)
De même une fois le token obtenu, j’ai renommé mon Bearer en Token :
Authorization : Token valeurDuJwt
Merci pour votre aide.
Me again. Please delete my posts. My bad! I think really there’s only two things one needs to be careful of:
(i) if you generate the public/private keys as suggested in the readme docs, you need to make sure you populate the passphrase in config.yml
(ii) you need to make sure you urlencode the passed token when you put in in the querystring.
Thanks. Its a great piece of code!
Bonjour Laurent,
Il y a deux étapes à distinguer : 1) la récupération d’un token et 2) l’utilisation de celui-ci.
La récupération d’un token se fait au moyen d’une authentification standard identifiant / mot de passe via un POST de formulaire (XHR).
Si l’authentification réussi, vous obtenez une réponse JSON contenant le JWT à renvoyer à chaque future requête au serveur en tant que Authorization Header.
Tout comme Laurent, je pense avoir un soucis de configuration et/ou de compréhension de tout ca.
J’utilise en front une app angular.js ou je gère le formulaire de login. Par contre j’ai un doute si je dois envoyer directement sur /login ou /login_check.
De plus si je dois vérifier que pour chaque chargement de route, l’utilisateur n’a pas déclencher un timeout, quel en serait l’idée ?
Merci pour votre aide
Salut Phil,
Les identifiants doivent être envoyés en POST sur le check_path du form_login de ton firewall (/login_check par défaut et dans l’exemple du README).
$http({
method: ‘POST’,
url: ‘/login_check’,
headers: {‘Content-Type’: ‘application/x-www-form-urlencoded’},
transformRequest: function (obj) {
var str = [];
for (var p in obj) {
str.push(encodeURIComponent(p) + « = » + encodeURIComponent(obj[p]));
}
return str.join(« & »);
},
data: {
username: ‘secret’,
password: ‘secret’
}
});
En ce qui concerne la gestion de l’expiration du token dans ton application AngularJS, tu peux te baser sur ce module : https://github.com/witoldsz/angular-http-auth qui fourni tout le nécessaire.
Bonjour,
j’ai un soucis, aucun token n’est envoyé j’ai l’erreur suivante : « net::ERR_CONNECTION_RESET » pourtant dans les logs symfony j’ai bien « User « admin » has been authenticated successfully ».
Une idée?
merci
Bonjour Axel,
Ton erreur semble plus liée à ton navigateur qu’au bundle lui-même.
As-tu testé la sandbox https://github.com/slashfan/LexikJWTAuthenticationBundleSandbox ?
Clone le projet et suis les instructions d’installation, tu devrais te retrouver avec une application de test parfaitement fonctionnelle.