web-dev-qa-db-fra.com

Comment puis-je décoder un google OAuth 2.0 JWT (OpenID Connect) dans une application de nœud?

J'ai beaucoup de mal ici à essayer d'utiliser google OAuth pour authentifier les utilisateurs dans mon application express de noeud. Je peux réussir OAuth, qui renvoie une réponse comme ceci:

{
  access_token: 'token string',
  id_token: 'id.string',
  expires_in: 3599,
  token_type: "Bearer"
}

Tout cela a du sens, mais je ne peux pas pour la vie de moi comprendre comment décoder le JWT. Je suis un peu inexpérimenté dans tout cela, donc tout cela m'est un peu étranger.

En suivant les instructions répertoriées ici: https://developers.google.com/accounts/docs/OAuth2Login#validatinganidtoken J'essaie de décoder le JWT localement dans mon application de nœud.

J'ai installé https://github.com/hokaccha/node-jwt-simple dans mon environnement de nœud.

Et je suis assez certain que je dois utiliser ce certificat ( https://www.googleapis.com/oauth2/v1/certs ) dans tout cela pour le décoder, mais je suis un peu d'une perte ici. Je ne comprends pas vraiment comment j'obtiens le certificat dans mon application de nœud, et ensuite comment l'utiliser avec node-jwt-simple. Et je ne comprends pas non plus vraiment comment je sais quand j'ai besoin d'extraire un nouveau certificat, par opposition à l'utilisation d'un certificat mis en cache.

Quelqu'un avec une certaine expérience dans ce domaine peut-il m'aider?

Merci pour toute aide. Je suis totalement perdu à ce stade.

** Mise à jour **

J'ai donc fait quelques progrès ... En quelque sorte. En appelant jwt.decode (id_token, certificate, true); Je suis capable de décoder avec succès le jeton. Même si le certificat var est un objet vide {}. Cela me laisse encore 3 questions. 1: Quelle est la meilleure façon d'obtenir le certificat dans mon application express en utilisant l'URL de Google? 2: Comment saurai-je quand j'aurai besoin d'en extraire une nouvelle version? 3: Il semble que passer vrai pour noVerify (3e argument dans jwt.decode) est une idée terrible. Comment puis-je faire en sorte que cela fonctionne sans le transmettre? Il semble que jwt-simple attend hs256 et que le jeton utilise rs256.

Encore une fois, je suis super inexpérimenté dans ce domaine, donc je suis peut-être loin de la base ici.

* MISE À JOUR * Grâce à l'aide de Nat, j'ai pu faire fonctionner cela! Je pense que j'ai essayé tous les modules de nœuds JWT et JWS. Ce sur quoi j'ai finalement atterri est le suivant: j'ai constaté qu'aucun des modules que j'ai examinés ne faisait tout à fait ce que je voulais hors de la boîte. J'ai créé les méthodes d'aide au décodage jwt suivantes que j'utilise pour décoder l'id_token, afin que je puisse obtenir l'enfant à partir de l'en-tête.

module.exports = {
  decodeJwt: function (token) {
    var segments = token.split('.');

    if (segments.length !== 3) {
      throw new Error('Not enough or too many segments');
    }

    // All segment should be base64
    var headerSeg = segments[0];
    var payloadSeg = segments[1];
    var signatureSeg = segments[2];

    // base64 decode and parse JSON
    var header = JSON.parse(base64urlDecode(headerSeg));
    var payload = JSON.parse(base64urlDecode(payloadSeg));

    return {
      header: header,
      payload: payload,
      signature: signatureSeg
    }

  }
}

function base64urlDecode(str) {
  return new Buffer(base64urlUnescape(str), 'base64').toString();
};

function base64urlUnescape(str) {
  str += Array(5 - str.length % 4).join('=');
  return str.replace(/\-/g, '+').replace(/_/g, '/');
}

J'utilise ce décodage pour déterminer si j'ai besoin d'extraire un nouveau certificat public à partir de: https://www.googleapis.com/oauth2/v1/certs

Ensuite, j'utilise ce certificat public et node-jws ( https://github.com/brianloveswords/node-jws ) jws.verify (id_token, cert) pour vérifier la signature!

Hourra! Merci encore pour l'explication supplémentaire que vous avez donnée dans votre réponse. Cela m'a beaucoup aidé à comprendre ce que j'essayais même de faire. J'espère que cela pourrait aussi aider les autres.

36
ThePuzzleMaster

Du point de vue des spécifications, ce que vous rencontrez est [OpenID Connect].

id_token est un [JWS] signé [JWT]. Dans ce cas, c'est un "." chaîne séparée avec trois composants. La première partie est l'en-tête. Le second est la charge utile. Le troisième est la signature. Chacun d'eux est une chaîne codée Base64url.

Lorsque vous décodez l'en-tête, vous obtiendrez quelque chose comme:

{"alg": "RS256", "kid": "43ebb53b0397e7aaf3087d6844e37d55c5fb1b67"}

"Alg" indique que l'algorithme de signature est RS256, qui est défini dans [JWA]. Le "kid" indique l'identifiant de la clé publique qui correspond à la clé utilisée pour signer.

Je suis maintenant prêt à répondre à certaines de vos questions:

2: Comment saurai-je quand j'aurai besoin d'en extraire une nouvelle version?

Lorsque le kid du fichier cert mis en cache (un fichier [JWK]) ne correspond pas au kid dans l'en-tête, récupérez un nouveau fichier cert. (BTW, l'URL à partir de laquelle vous tirez les certificats est appelée x5u.)

3: Il semble que passer vrai pour noVerify (3e argument dans jwt.decode) est une idée terrible. Comment puis-je faire en sorte que cela fonctionne sans le transmettre?

En effet. Vous voudrez peut-être regarder une autre bibliothèque telle que kjur.github.io/jsjws/.

Références

  • [OpenID Connect] openid.bitbucket.org/openid-connect-core-1_0.html
  • [JWS] tools.ietf.org/html/draft-ietf-jose-json-web-signature
  • [JWT] tools.ietf.org/html/draft-ietf-oauth-json-web-token
  • [JWK] tools.ietf.org/html/draft-ietf-oauth-json-web-keys
  • [JWA] tools.ietf.org/html/draft-ietf-jose-json-web-algorithms
54
Nat Sakimura