Подтвердить что ты не робот

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

У меня есть время, пытаясь использовать Google OAuth для аутентификации пользователей в моем экспресс-приложении node. Я могу успешно выполнить 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 локально в приложении node.

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

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

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

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

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

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

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

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

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.verify(id_token, cert), чтобы проверить подпись!

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

4b9b3361

Ответ 1

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

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

Когда вы декодируете заголовок, вы получите что-то вроде:

{ "ALG": "RS256", "ребенок": "43ebb53b0397e7aaf3087d6844e37d55c5fb1b67" }

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

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

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

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

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

Действительно. Возможно, вам захочется взглянуть на другую библиотеку, такую ​​как kjur.github.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
  • [JWA] tools.ietf.org/html/draft-ietf-jose-json-web-algorithms