Fermer

décembre 4, 2018

Comment créer et vérifier des JWT avec un nœud –


Cet article a été publié à l'origine sur sur le blog des développeurs d'Okta . Merci de soutenir les partenaires qui rendent SitePoint possible.

L’authentification sur Internet a beaucoup évolué au fil des ans. Il existe de nombreuses façons de le faire, mais ce qui a bien fonctionné dans les années 90 ne le permet pas vraiment. Dans ce tutoriel, je couvrirai brièvement certaines formes d’authentification plus anciennes et plus simples, puis je vous montrerai comment une approche plus moderne et plus sécurisée. À la fin de cet article, vous pourrez créer et vérifier vous-même des JWT dans Node. Je vais également vous montrer comment vous pouvez utiliser Okta pour tout faire pour vous dans les coulisses.

Traditionnellement, le moyen le plus simple de faire une autorisation est d'utiliser un nom d'utilisateur et un mot de passe. Ceci s'appelle l'autorisation de base et se fait simplement en envoyant nom d'utilisateur: mot de passe sous forme de chaîne codée pouvant être décodée par quiconque le recherchant. Vous pourriez considérer cette chaîne comme un "jeton". Le problème est que vous envoyez votre mot de passe à chaque demande. Vous pouvez également envoyer votre nom d'utilisateur et votre mot de passe une seule fois et laisser le serveur créer un ID de session pour vous. Le client enverrait alors cet ID avec chaque demande au lieu d'un nom d'utilisateur et d'un mot de passe. Cette méthode fonctionne également, mais le client peut avoir du mal à stocker et à gérer des sessions, en particulier pour les grands groupes d’utilisateurs.

La troisième méthode de gestion des autorisations consiste à utiliser des jetons Web JSON ou JWT. Les JWT sont devenus la norme de facto au cours des dernières années. Un JWT fait un ensemble de revendications (par exemple, «Je suis Abe Froman, le roi des saucisses de Chicago») qui peuvent être vérifiées. Comme les autorisations de base, les revendications peuvent être lues par n’importe qui. Cependant, contrairement à Basic Auth, vous ne partagerez pas votre mot de passe avec les personnes qui l'écoutent. Au lieu de cela, il s'agit de confiance.

Confiance, mais vérifiez… Votre JWTs

 doit être vrai

OK , peut-être ne croyez pas tout ce que vous lisez sur Internet. Vous vous demandez peut-être comment une personne peut simplement faire des déclarations et s’attendre à ce que le serveur les croie. Lorsque vous effectuez une réclamation à l'aide d'un fichier JWT, celui-ci est signé par un serveur doté d'une clé secrète. Le serveur qui lit la clé peut facilement vérifier que la demande est valide, même sans connaître le secret utilisé. Cependant, il serait presque impossible pour quelqu'un de modifier les revendications et de s'assurer de la validité de la signature sans avoir accès à cette clé secrète.

Pourquoi utiliser un JWT?

L'utilisation d'un JWT permet à un serveur de décharger l'authentification d'un serveur. 3ème partie ils ont confiance. Tant que vous faites confiance au tiers, vous pouvez le laisser s'assurer que l'utilisateur est bien ce qu'il dit. Cette tierce partie créera alors un fichier JWT à transmettre à votre serveur, avec toutes les informations nécessaires. Cela comprend généralement au moins l'identifiant de l'utilisateur (généralement appelé sub pour “sujet”), “l'émetteur” ( iss ) du jeton et le “délai d'expiration”. ( exp ). Il y a pas mal de revendications standardisées, mais vous pouvez vraiment mettre n'importe quel JSON dans une revendication. N'oubliez pas que plus vous incluez d'informations, plus le jeton sera long.

Création d'une application de nœud simple

Pour créer et vérifier vos propres fichiers JWT, vous devez d'abord configurer un serveur de nœud. n'a pas à, mais c'est ce que je vais vous apprendre aujourd'hui). Pour commencer, exécutez les commandes suivantes pour configurer un nouveau projet:

 mkdir fun-with-jwts
cd fun-with-jwts
npm init -y
npm install express@4.16.4
npm install -D nodemon@1.18.6

Créez ensuite un nouveau fichier index.js qui contiendra un serveur de noeud super simple. Il y a trois points de terminaison ici, qui sont simplement annotés avec TODO comme notes pour ce qu’il faut mettre en œuvre.

Le point de terminaison / create nécessitera une autorisation de base pour vous connecter. vous écriviez un vrai serveur OAuth, vous utiliseriez probablement autre chose que Basic Auth. Vous devez également rechercher l'utilisateur dans une base de données et vous assurer qu'il a fourni le bon mot de passe. Pour que la démo reste simple, je viens de coder en dur un nom d'utilisateur et un mot de passe afin que nous puissions nous concentrer sur la fonctionnalité JWT.

Le noeud final / verify prend un JWT comme paramètre. à décoder.

 const express = require ('express')
const app = express ()
const port = process.env.PORT || 3000

app.get ('/ create', (req, res) => {
  if (req.headers.authorization! == 'Basic QXp1cmVEaWFtb25kOmh1bnRlcjI =') {
    res.set ('WWW-Authenticate', 'Royaume de base = "401"')
    res.status (401) .send ('Essayez un utilisateur: AzureDiamond, mot de passe: hunter2')
    revenir
  }

  res.send ('TODO: créer un JWT')
})

app.get ('/ verify /: token', (req, res) => {
  res.send (`TODO: vérifiez ce JWT: $ {req.params.token}`)
})

app.get ('/', (req, res) => res.send ('TODO: utilisez Okta pour auth'))

app.listen (port, () => console.log (`le serveur JWT écoute sur le port $ {port}!`))

Vous pouvez maintenant exécuter le serveur en tapant node_modules / .bin / nodemon. . Cela démarrera un serveur sur le port 3000 et redémarrera automatiquement lorsque vous apporterez des modifications à votre code source. Vous pouvez y accéder en accédant à http: // localhost: 3000 dans votre navigateur. Pour atteindre les différents points de terminaison, vous devez modifier l’URL en http: // localhost: 3000 / create ou http: // localhost: 3000 / verify / asdf . Si vous préférez travailler en ligne de commande, vous pouvez utiliser curl pour atteindre tous ces points de terminaison:

 $ curl localhost: 3000
TODO: utilisez Okta pour l'authentification

$ curl localhost: 3000 / create
Essayez un utilisateur: AzureDiamond, mot de passe: hunter2

$ curl AzureDiamond: hunter2 @ localhost: 3000 / create
TODO: créer un JWT

$ curl localhost: 3000 / verify / asdf
TODO: vérifiez ce JWT: asdf

Création de jetons Web JSON dans votre application de nœud

Un jeton Web JSON est composé de trois parties. L'en-tête la charge utile et la signature séparés par . s.

L'entête d'en-tête est un objet JSON codé en base64 spécifiant l'algorithme à utiliser et le type du jeton.

La charge utile est également un objet JSON codé en base64 contenant à peu près tout ce que vous voulez. En règle générale, il contient au moins un horodatage et des informations d'identification.

La signature hache l'en-tête, la charge utile et une clé secrète en utilisant l'algorithme spécifié dans l'en-tête.

Il y a un certain nombre d’outils disponibles pour créer des JWT pour différentes langues. Pour Node, un exemple simple est Njwt . Pour l'ajouter à votre projet, exécutez

 npm install njwt@0.4.0

Remplacez maintenant la ligne res.send ('TODO: créer un JWT') dans index.js par la suivante:

 const jwt = require ('njwt' )
  const claims = {iss: 'fun-with-jwts', sous: 'AzureDiamond'}
  const token = jwt.create (revendications, 'expression top-secrète')
  token.setExpiration (new Date (). getTime () + 60 * 1000)
  res.send (token.compact ())

N'hésitez pas à jouer avec la charge utile. Avec la fonction setExpiration () ci-dessus, le jeton expirera dans une minute, ce qui vous permettra de voir ce qu'il se passe quand il expirera, sans avoir à attendre trop longtemps.

Pour le tester et obtenir une jeton, connectez-vous via le noeud final / create . Encore une fois, vous pouvez aller sur votre navigateur à http: // localhost: 3000 / create ou utiliser curl:

 $ curl AzureDiamond: hunter2 @ localhost: 3000 / create
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkISIsIm51bWJlciI6MC41MzgyNzE0MTk3Nzg5NDc4LCJpYXQiOjE1NDIxMDQ0NDgsImV4cCI6MTU0MjEwNDUwOCwiaXNzIjoiZnVuLXdpdGgtand0cyIsInN1YiI6IkF6dXJlRGlhbW9uZCJ9.LRVmeIzAYk5WbDoKfSTYwPx5iW0omuB76Qud-xR8We4

Vérifiez les jetons Web JSON dans votre application de nœud

Eh bien, cela ressemble un peu au charabia. Vous pouvez voir qu'il y a deux . dans le JWT, séparant l'en-tête, la charge utile et la signature, mais ce n'est pas lisible par l'homme. L'étape suivante consiste à écrire quelque chose pour décoder cette chaîne en quelque chose qui rend un peu plus lisible.

Remplacez la ligne contenant TODO: vérifiez ce JWT avec ce qui suit:

 const jwt = require ( 'njwt')
  const {token} = req.params
  jwt.verify (jeton, 'expression top-secrète', (err, vérifiéJwt) => {
    si (err) {
      res.send (err.message)
    }autre{
      res.send (vérifiéJwt)
    }
  })

Dans la route / verify /: token la partie : token indique à Express que vous souhaitez lire cette section de l'URL sous forme de paramètre afin de pouvoir l'obtenir. sur req.params.token . Vous pouvez ensuite utiliser njwt pour essayer de vérifier le jeton. Si cela échoue, cela peut signifier plusieurs choses, comme le jeton a été mal formé ou a expiré.

De retour sur votre site Web ou en boucle, créez un autre jeton en utilisant http: // localhost: 3000 / create . Copiez et collez ensuite cette information dans l'URL afin d'obtenir http: // localhost: 3000 / verify / eyJhb ... R8We4 . Vous devriez obtenir quelque chose comme ceci:

 {
  "en-tête": {"typ": "JWT", "alg": "HS256"},
  "corps": {
    "iss": "fun-with-jwts",
    "sub": "AzureDiamond",
    "jti": "3668a38b-d25d-47ee-8da2-19a36d51e3da",
    "iat": 1542146783,
    "exp": 1542146843
  }
}

Si vous attendez une minute et essayez à nouveau, vous obtiendrez plutôt jwt expiré .

Ajoutez un middleware OIDC à votre application de nœud pour gérer les fonctionnalités de JWT

Eh bien, ce n'était pas le cas mal. Mais j'ai bien sûr passé sous silence beaucoup de détails. Cette phrase top-secrète n’est pas vraiment très secrète. Comment vous assurez-vous d’en avoir un sécurisé et que ce n’est pas facile à trouver? Qu'en est-il de toutes les autres options JWT? Comment stockez-vous cela dans un navigateur? Quel est le délai d’expiration optimal pour un jeton?

C’est là que Okta entre en jeu. Plutôt que de gérer vous-même tout cela, vous pouvez utiliser le service cloud d’Okta pour gérer tout cela pour vous. Après quelques minutes d’installation, vous pouvez cesser de penser à la sécurisation de votre application et vous concentrer uniquement sur ce qui la rend unique.

Pourquoi Auth avec Okta?

Okta est un service en nuage qui permet aux développeurs de créer, d’éditer des modifications. , et en toute sécurité stocker des comptes d'utilisateurs et des données de compte d'utilisateur, et les connecter avec une ou plusieurs applications. Notre API vous permet de:

Si vous n'en avez pas déjà, ouvrez un compte développeur gratuit pour toujours .

Créez un serveur Okta

. enregistrer des informations à utiliser dans votre application. Créez un nouveau fichier nommé .env . Entrez-y l'URL de votre organisation Okta.

 HOST_URL = http: // localhost: 3000
OKTA_ORG_URL = https: // {votreOktaOrgUrl}

Vous aurez également besoin d'une chaîne aléatoire à utiliser comme secret d'application pour les sessions. Vous pouvez le générer avec les commandes suivantes:

 npm install -g uuid-cli
echo "APP_SECRET =` uuid` "" >> .env

Ensuite, connectez-vous à votre console de développeur, accédez à Applications puis cliquez sur Ajouter une application . Sélectionnez Web puis cliquez sur Suivant . Donnez à votre application un nom, tel que "Fun with JWTs". Remplacez l'URI de base par http: // localhost: 3000 / et l'URI de redirection de connexion par http: // localhost: 3000 / implicite / Rappel puis cliquez sur Terminé

Cliquez sur Modifiez et ajoutez un Déconnexion URI de http: // localhost: 3000 / puis cliquez sur . Enregistrer .

 Paramètres de l'application okta

La page que vous consultez après la création d'une application contient des informations supplémentaires que vous devez enregistrer dans votre . Fichier .env . Copiez l'ID et le secret du client.

 OKTA_CLIENT_ID = {yourClientId}
OKTA_CLIENT_SECRET = {votreClientSecret}

Revenons maintenant au code. Vous devez ajouter le middleware OIDC d’Okta pour contrôler l’authentification. Il repose également sur l'utilisation de sessions. Vous devez utiliser dotenv pour lire les variables du fichier .env . Pour installer les dépendances dont vous aurez besoin, exécutez la commande suivante:

 npm install @ okta / oidc-middleware @ 1.0.2 dotenv@6.1.0 express-session@1.15.6

Tout en haut de votre fichier index.js vous devez inclure dotenv . Cela fera en sorte que les secrets de votre fichier .env puissent être lus par votre programme. Ajoutez cette ligne avant toute autre chose:

 require ('dotenv'). Config ()

Pour que Okta soit configuré en toute sécurité, vous devez dire à Express d’utiliser le middleware OIDC d’Okta, qui nécessite également des sessions. Recherchez la ligne contenant TODO: utilisez Okta pour authentifier dans votre fichier index.js puis entrez la ligne suivante juste au-dessus pour initialiser Okta avec toutes vos variables d'environnement:

 const session = require ('express-session')
const {ExpressOIDC} = require ('@ okta / oidc-middleware')

app.use (session ({
  secret: process.env.APP_SECRET,
  resave: true,
  saveUninitialized: false
}))

const oidc = new ExpressOIDC ({
  émetteur: `$ {process.env.OKTA_ORG_URL} / oauth2 / default`,
  client_id: process.env.OKTA_CLIENT_ID,
  client_secret: process.env.OKTA_CLIENT_SECRET,
  redirect_uri: `$ {process.env.HOST_URL} / code d'autorisation / callback`,
  portée: 'profil ouvert'
})

app.use (oidc.router)

Maintenant que vous êtes tous installés, créer des itinéraires sécurisés devient un jeu d’enfant! Pour le tester, remplacez la ligne restante TODO: utilisez Okta pour la ligne autorisée avec un itinéraire comme celui-ci:

 app.get ('/', oidc.ensureAuthenticated (), (req, res) => res.send ('Peekaboo!'))

Lorsque vous accédez à http: // localhost: 3000 vous serez redirigé vers une page de connexion sécurisée. Comme vous êtes probablement toujours connecté à Okta à partir du panneau d'administration, vous devrez peut-être utiliser un navigateur différent ou une fenêtre de navigation privée pour afficher l'écran de connexion, comme le feraient d'autres visiteurs de votre site.

Une fois que vous vous êtes connecté, vous aurez un message caché!

En savoir plus sur les nœuds, les JWT et la gestion sécurisée des utilisateurs

Vous pouvez certainement faire beaucoup plus de travail que d'imprimer Peekaboo! mais l’essentiel à retenir ici est que, après une configuration rapide, vous pouvez ajouter une authentification à n’importe quel itinéraire de votre serveur Express en ajoutant un simple oidc.ensureAuthenticated () . Okta s'occupe de la gestion des utilisateurs, du stockage des sessions, de la création et de la vérification des JWT, vous n'avez donc pas à le faire!

Si vous souhaitez en savoir plus sur les JWT ou Node, consultez quelques-uns de ces autres messages sur le développeur Okta. blog:

Si vous avez des questions sur cette publication, veuillez ajouter un commentaire ci-dessous. Pour un contenu plus génial, suivez @oktadev sur Twitter, comme nous sur Facebook ou abonnez-vous à sur notre chaîne YouTube .






Source link