如何在节点应用中解码Google OAuth 2.0 JWT(OpenID Connect)?

The*_*ter 36 google-openid node.js express jwt google-oauth

我在这里尝试使用谷歌OAuth来验证我的节点快递应用程序中的用户.我可以成功执行OAuth,它会返回如下响应:

{
  access_token: 'token string',
  id_token: 'id.string',
  expires_in: 3599,
  token_type: "Bearer"
}
Run Code Online (Sandbox Code Playgroud)

这一切都有道理,但我不能为我的生活弄清楚如何解码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.decode(id_token,certificate,true); 我能够成功解码令牌.即使证书var是一个空对象{}.这给我留下了3个问题.1:使用谷歌网址将证书送入我的快递应用程序的最佳方法是什么?2:我怎么知道何时需要提供它的新版本?3:似乎传递给noVerify(jwt.decode中的第3个arg)的真实是一个糟糕的主意.如何在不通过的情况下实现这一目标?看起来似乎jwt-simple期待hs256并且令牌正在使用rs256.

再一次,我对此缺乏经验,所以我可能会离开这里.

*更新* 感谢Nat的帮助,我得到了这个工作!我想我尝试了每一个JWT和JWS节点模块.我最终登陆的内容如下:我发现我所看到的所有模块都没有完全符合我的想法.我创建了以下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, '/');
}
Run Code Online (Sandbox Code Playgroud)

我正在使用此解码来确定是否需要从以下位置获取新的公共证书:https://www.googleapis.com/oauth2/v1/certs

然后我使用公共证书和node-jws(https://github.com/brianloveswords/node-jws)jws.verify(id_token,cert)来验证签名!

万岁!再次感谢您在回复中提供的额外解释.这对帮助我理解我甚至想要做的事情有很大帮助.希望这也可以帮助别人.

Nat*_*ura 54

从规范的角度来看,您遇到的是[OpenID Connect].

id_token是[JWS]签名[JWT].在这种情况下,它是一个"." 用三个组件分隔的字符串.第一部分是标题.第二个是有效载荷.第三是签名.它们中的每一个都是Base64url编码的字符串.

解码标题时,您将获得如下内容:

{ "ALG": "RS256", "孩子": "43ebb53b0397e7aaf3087d6844e37d55c5fb1b67"}

"alg"表示签名算法是RS256,其在[JWA]中定义."kid"表示与用于签名的密钥对应的公钥的密钥id.

现在我准备回答你的一些问题:

2:我怎么知道何时需要提供它的新版本?

当缓存的证书文件([JWK]文件)的孩子与标题中的孩子不匹配时,获取新的证书文件.(顺便说一句,您从中提取证书的URL称为x5u.)

3:似乎传递给noVerify(jwt.decode中的第3个arg)的真实是一个糟糕的主意.如何在不通过的情况下实现这一目标?

确实.也许您可能想要查看另一个库,例如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
  • [JWK] tools.ietf.org/html/draft-ietf-oauth-json-web-keys
  • [JWA] tools.ietf.org/html/draft-ietf-jose-json-web-algorithms