用于Firebase Admin SDK的Node.js身份验证服务器 - JWT验证问题 [英] Node.js authentication server for Firebase Admin SDK - JWT validation issue

查看:245
本文介绍了用于Firebase Admin SDK的Node.js身份验证服务器 - JWT验证问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一个项目,我们将在微服务架构中使用不同的服务,我们也想使用一些Firebase服务。我正在开发一个auth服务器,这个服务器将用于在Firebase以及其他API项目中使用自定义JWT。

我们想使用Firebase Auth SDK轻松整合FB,Google,Twitter等,但是我们需要用更多的数据来丰富用户的代币。因此,我的思考过程是创建一个使用Firebase Admin SDK的Node.JS auth服务器来执行此操作。流程将如下所示:

$ ol

  • 用户使用最喜欢的提供程序登录客户端
  • 如果登录成功,用户从Firebase收到JWT。这被发送到auth服务器进行验证。如果auth服务器可以使用admin SDK验证令牌,则创建一个新的自定义令牌,并添加更多数据,并将此新自定义令牌返回给客户端

  • 让客户端使用新的自定义令牌重新进行身份验证,并将其用于与Firebase以及我们的其他API项目(主要位于.NET Core)进行通信。 / li>

    步骤1-3正常工作。 在尝试验证其他服务上的自定义标记时出现问题。

    TL; DR :有两个问题:


    1. 验证使用Firebase Node.JS Admin SDK发出的自定义令牌时,应该使用什么作为公钥?从Google公开的JWK中提取的密钥,或从用于签名的私钥中提取的密钥?

    2. 如果使用JWK方法,我应该如何构建自定义标记, code> kid 标题






    ,我怀疑验证它的正确方法。 (请原谅,我没有那么有经验的创建OAuth流。)使用的算法是RS256,所以我应该能够使用公钥验证令牌。正如我所看到的,有两种方法可以得到这个密钥:


    1. 从私钥中提取公钥并使用它进行验证。我可以在auth服务器上的测试终端上成功地进行验证,但是我觉得这是不正确的做法。
    2. 另一种更正确的方法是使用令牌中的值在我的项目的Google的/.well-known/openid-configuration/端点上查找JWK,即


      https://securetoken.google.com/[PROJECT ID] /。well-known / openid-configuration



      检索指数和模数正确 kid (密钥ID),并从这些密钥创建公钥。

      通过执行admin admin生成的令牌
      $ b

        admin。 auth()。createCustomToken(uid,additionalClaims).then(function(customToken)

      看起来像这样:

      标题:

      $ p $ {
      alg:RS256,
      typ:JWT
      }

      有效载荷:

        {
      声明:{
      premiumAccount:true,
      someRandomInnerObject:{
      something:somethingRandom
      }
      },
      uid:< uid for the user>,
      iat:1488454663,
      exp:1488458263,
      aud:https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit,
      iss:firebase-adminsdk-le7ge @< PROJECT ID> .iam.gserviceaccount.com,
      sub:firebase-adminsdk-le7ge @< PROJECT ID> .iam。 gserviceaccount.com

      我但似乎无法得到方法2的工作。一个问题是生成的标记没有 kid 标题,所以不符合OpenID规范(AFAIK),这导致了两种选择之一:


      1. 使用上面的第一种方法。这会导致问题 - 如果由于某种原因需要撤销或重置auth服务器上的私钥,则需要执行此操作,并将更改部署到所有其他服务上,从而使解决方案的动态性更低,更容易出错。

      2. 使用jwt.io中提到的某个库手动生成一个类似的标记,并将原始Firebase标识标记中的孩子添加到标题中。


        第二个问题:


        • 那么我应该把什么作为iss,aud和sub呢?与管理SDK相同的值呢?如果是这样,是不是作弊,因为他们不再是发行人?

        • 我试了一下(生成一个类似的令牌副本,但添加 kid 的原始令牌),我似乎无法验证使用创建的孩子的PEM密钥生成的令牌。



        我这样做的方式是这样的(在
        / google-id-token-from-a-server /rel =nofollow noreferrertitle =blog guide


        1. 转至 https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com ,然后检索相关小孩的模数(n)和指数(e) b $ b
        2. 使用lib生成公钥( rsa- pem-from-mod-exp

        3. 使用键验证使用'official'jwt lib



          以上结果公开关键是这样的:

          ----- BEGI ÑRSA公钥-----
          MIIBCgKCAQEAxXpo7ChLMnv1QTovmm9DkAnYgINO1WFBWGAVRt93ajftPpVNcxMT
          MAQI4Jf06OxFCQib94GyHxKDNOYiweVrHVYH9j / STF + xbQwiPF / 8L7 + haC2WXMl2
          tkTgmslVewWuYwpfm4CoQFV29OVGWCqwEcbCaycWVddm1ykdryXzNTqfzCyrSZdZ
          k0yoE0Q1GDcuUl / 6tjH1gAfzN6c8wPvI2YDhc5gIHm04BcLVVMBXnC0hxgjbJbN4
          zg2QafiUpICZzonOUbK6 + rrIFGfHpcv8mWG1Awsu5qs33aFu1Qx / 4LdMAuEsvX9f
          EmFZCUS8 + trilqJbcsd / AQ9eOZLAB0BdKwIDAQAB
          -----结束RSA PUBLIC KEY -----




        <两件事似乎是错的。一个是关键不同于我可以从私钥中提取的关键。另一个是我从私钥中提取的那个有这些注释:

          ----- BEGIN PUBLIC KEY- ---- 
        -----结束公钥-----

        没有RSA。这很重要吗?无论如何,它不验证。

        最后,我是否完全误解了OpenID流程? JWK是否还需要私钥才能验证我的JWT?我是否应该在自己的auth服务器上公开自己的JWK,以便其他服务可以联系并使用,而不是使用Google的?我对Firebase Admin SDK的功能有些困惑,我认为: - )我知道这是很多问题,但是我认为他们都是相关的。

        我在研究中所依赖的一些资源(除了官方的sdk docs of course):


        解决方案

        使用自定义令牌重新验证Firebase客户端SDK,客户端实际上会生成一个新的ID令牌,其中包含来自自定义令牌的声明。此ID令牌是您应该用来验证对不同微服务的请求(记录在此处)。所以是的,你的原始ID令牌被丢弃了,但是在它的地方创建了一个新的ID令牌。那个ID令牌将会每小时自动刷新一次。因此,您应该只需致电 用户.getToken() 来获得一个有效的ID令牌,只要你需要它。该方法代表您处理所有缓存。


        I am working on a project where we are going to be using different services in a microservice architecture, and we would like to also use some Firebase services. I am working on an auth server that is going to mint custom JWT's for use in both Firebase, as well as the other API projects.

        We would like to use the Firebase Auth SDK to easily integrate with FB, Google, Twitter etc, but we need to enrich the user's token with more data. Therefore, my thought process is that I'd create a Node.JS auth server that uses the Firebase Admin SDK to do this. The flow would be as follows:

        1. User logs in with favourite provider on client
        2. If login is succesful, the user receives a JWT from Firebase. This is sent to the auth server for validation
        3. If the auth server can validate the token using the admin SDK, create a new custom token enriched with more data, and return this new custom token to the client
        4. Have client re-authenticate with the new custom token, and use it for communication with both Firebase as well as our other API projects (which will mainly be in .NET Core)

        Step 1-3 works fine. The problem arises when trying to verify the custom token on the other services.

        TL;DR : There are two questions inhere:

        1. When validating custom tokens issued using the Firebase Node.JS Admin SDK, what should I use as the public key? A key extracted from Google's exposed JWK's, or a key extracted from the private key that is used to sign?
        2. In case of the JWK approach, how should I construct the custom token with a kid header?


        First, I am in doubt of the proper way to verify it. (Please excuse me, I'm not that experienced creating OAuth flows.) The algorithm used is RS256, so I should be able to verify the token using a public key. As I see it, there are two ways to get this key:

        1. Extract the public key from the private key and verify using this. I can do this and verify successfully on a test endpoint on my auth server, however I feel this is the incorrect way to do it
        2. The other, and more correct way I think, is to use the values from the token to find the JWK's on Google's "/.well-known/openid-configuration/" endpoint for my project, , i.e.

        https: //securetoken.google.com/[PROJECT ID]/.well-known/openid-configuration

        to retrieve the exponent and modulus for the correct kid (key ID) and create the public key from those.

        The token generated from the admin SDK by doing

        admin.auth().createCustomToken(uid, additionalClaims).then(function(customToken)
        

        with some custom claims looks something like this:

        headers:

        {
          "alg": "RS256",
          "typ": "JWT"
        }
        

        payload:

        {
          "claims": {
            "premiumAccount": true,
            "someRandomInnerObject": {
              "something": "somethingRandom"
            }
          },
          "uid": "<uid for the user>",
          "iat": 1488454663,
          "exp": 1488458263,
          "aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
          "iss": "firebase-adminsdk-le7ge@<PROJECT ID>.iam.gserviceaccount.com",
          "sub": "firebase-adminsdk-le7ge@<PROJECT ID>.iam.gserviceaccount.com"
        }
        

        I can't seem to get method 2 to work, though. One problem is that the generated token does not have a kid header, and so does not conform to the OpenID spec (AFAIK), which leads to one of two options:

        1. Go with the first approach above. This leads to problems though - if I for some reason need to revoke or reset the private key on the auth server, I need to do it and deploy the changes on all the other services too, making the solution less dynamic and more error-prone.
        2. Generate a similar token manually using one of the libs mentioned at jwt.io, and add the kid from the original Firebase ID token to it's headers.

        Problems with number 2:

        • What should I put as iss, aud and sub, then? The same values as the admin SDK does? If so, isn't that 'cheating', as they are no longer the issuer?
        • I've tried it (generating a similar copy of the token, but adding the kid of the original token), and I can't seem to verify the generated token using the created PEM key for the kid.

        The way I do the latter is this (following a blog guide on the subject):

        1. Go to https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com and retrieve the modulus (n) and exponent (e) for the relevant kid
        2. Generate the public key using a lib (rsa-pem-from-mod-exp)
        3. Use the key to verify using the 'official' jwt lib

          The above results in a public key as such:

          -----BEGIN RSA PUBLIC KEY----- MIIBCgKCAQEAxXpo7ChLMnv1QTovmm9DkAnYgINO1WFBWGAVRt93ajftPpVNcxMT MAQI4Jf06OxFCQib94GyHxKDNOYiweVrHVYH9j/STF+xbQwiPF/8L7+haC2WXMl2 tkTgmslVewWuYwpfm4CoQFV29OVGWCqwEcbCaycWVddm1ykdryXzNTqfzCyrSZdZ k0yoE0Q1GDcuUl/6tjH1gAfzN6c8wPvI2YDhc5gIHm04BcLVVMBXnC0hxgjbJbN4 zg2QafiUpICZzonOUbK6+rrIFGfHpcv8mWG1Awsu5qs33aFu1Qx/4LdMAuEsvX9f EmFZCUS8+trilqJbcsd/AQ9eOZLAB0BdKwIDAQAB -----END RSA PUBLIC KEY-----

        Two things seem to be wrong. One is that the key is different from the one I can extract from the private key. The other is that the one I extract from the private key has these comments instead:

        -----BEGIN PUBLIC KEY-----
        -----END PUBLIC KEY-----
        

        with no 'RSA'. Does this matter? In any case, it doesn't verify.

        Finally, did I misunderstand the OpenID flow completely? Are the JWKs generated from a private key that I need as well to verify my JWTs? Should I expose my own JWKs on my auth server for the other services to contact and use instead of Google's? I'm a bit confused as to what the Firebase Admin SDK does and doesn't do, I think :-)

        I know this is a lot of questions, but I think they're all related.

        Some resources I've relied on in my research (besides the official admin sdk docs ofcourse):

        解决方案

        After re-authenticating the Firebase client SDK with the custom token, the client actually generates a new ID token with the claims from the custom token. This ID token is what you should use to verify requests made to your different microservices (documented here). So yes, your original ID token is discarded, but a new one is created in its place. And that ID token will be automatically refreshed every hour. So, you should be able to just call user.getToken() to get a valid ID token whenever you need it. That method handles all the caching on your behalf.

        这篇关于用于Firebase Admin SDK的Node.js身份验证服务器 - JWT验证问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆