Как я могу декодировать google OAuth 2.0 JWT (OpenID Connect) в приложении узла?

у меня здесь чертовски много времени, пытаясь использовать google OAuth для аутентификации пользователей в моем приложении Node express. Я могу успешно сделать OAuth, который возвращает ответ следующим образом:

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

все это имеет смысл, но я не могу для жизни меня понять, как декодировать JWT. Я немного неопытен во всем этом, поэтому все это немного чуждо мне.

следуя инструкциям, приведенным здесь: https://developers.google.com/accounts/docs/OAuth2Login#validatinganidtoken я пытаюсь декодировать JWT локально в моем приложении узла.

Я установил https://github.com/hokaccha/node-jwt-simple в моей среде узла.

и я уверен, что мне нужно использовать этот сертификат (https://www.googleapis.com/oauth2/v1/certs) во всем этом как-то расшифровать его, но я здесь немного в растерянности. Я действительно не понимаю, как я получите сертификат в мое приложение узла, и после этого, как использовать его с node-jwt-simple. И я также не понимаю, как я знаю,когда мне нужно вытащить новый сертификат, а не использовать кэшированный.

кто-нибудь там с некоторым опытом в этом, что может мне помочь?

Спасибо за любую помощь. Я в полной растерянности.

** обновление **

Итак, я добился некоторого прогресса... Вроде. Позвонив в jwt.декодировать (id_token, сертификат, true); Я могу успешно расшифровать токен. Даже если сертификат var является пустым объектом {}. Это оставляет мне еще 3 вопроса. 1: каков наилучший способ получить сертификат в мое экспресс-приложение, используя url-адрес от google? 2:Как я узнаю, когда мне нужно вытащить новую версию? 3: Похоже, что переход в true для noVerify (3-й arg в jwt.decode) - ужасная идея. Как я могу заставить это работать, не передавая это? Похоже, что, возможно, jwt-simple ожидает hs256 и маркер использует rs256.

опять же, я супер неопытен в этом, поэтому я могу быть далеко от базы здесь.

* обновление * Благодаря помощи Nat, я смог заставить это работать! Я думаю, что я пробовал каждый модуль узла JWT и JWS. В конце концов я приземлился на следующее:: Я обнаружил, что ни один из модулей, на которые я смотрел, не делал того, что я хотел из коробки. Я создал следующие вспомогательные методы декодирования JWT, которые я использую для декодирования маркер, так что я могу получить ребенка из заголовка.

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, '/');
}

Я использую это декодирование, чтобы определить, нужно ли мне вытаскивать новый публичный сертификат из:https://www.googleapis.com/oauth2/v1/certs

тогда я использую этот публичный сертификат и node-jws (https://github.com/brianloveswords/node-jws) jws.проверьте (id_token, cert), чтобы проверить подпись!

Ура! Еще раз спасибо за дополнительное объяснение, которое вы дали в своем ответе. Вот и пошла долгий путь, чтобы помочь мне понять, что я даже пытался сделать. Надеюсь, это поможет и другим.

1 ответов


с точки зрения спецификации, вы сталкиваетесь с [OpenID Connect].

id_token-это [JWS] со знаком [JWT]. В данном случае, это ".- разделенная струна с тремя компонентами. Первая часть-заголовок. Второй-полезная нагрузка. Третья подпись. Каждый из них-строка в кодировке Base64url.

когда вы расшифровать заголовок, вы получите что-то вроде:

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

"alg" указывает, что алгоритм подписи RS256, который определен в [JWA]. "Kid" указывает идентификатор ключа открытого ключа, который соответствует ключу, используемому для подписи.

теперь я готов ответить на некоторые ваши вопросы:

2:Как я узнаю, когда мне нужно вытащить новую версию?

когда ребенок кэшируется файл сертификата (файл [JWK]) не соответствует малышу в заголовке, получить новый файл сертификата. (Кстати, URL, из которого вы вытаскиваете сертификаты, называется x5u.)

3: Похоже, что передача true для noVerify (3rd arg в jwt.декодировать) это ужасная идея. Как я могу заставить это работать, не передавая это внутрь?

действительно. Возможно, вы захотите взглянуть на другую библиотеку, такую как kjur.гитуб.io/ jsjws/.

ссылки

  • [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