Node.js Firebase Admin SDK 的身份验证服务器 - JWT 验证问题
Node.js authentication server for Firebase Admin SDK - JWT validation issue
我正在做一个项目,我们将在微服务架构中使用不同的服务,我们还想使用一些 Firebase 服务。我正在开发一个身份验证服务器,该服务器将创建自定义 JWT 以用于 Firebase 以及其他 API 项目。
我们想使用 Firebase Auth SDK 轻松与 FB、Google、Twitter 等集成,但我们需要用更多数据丰富用户的令牌。因此,我的想法是创建一个 Node.JS 身份验证服务器,它使用 Firebase Admin SDK 来执行此操作。流程如下:
- 用户在客户端使用最喜欢的提供商登录
- 如果登录成功,用户会收到来自 Firebase 的 JWT。这被发送到 auth 服务器进行验证
- 如果授权服务器可以使用管理 SDK 验证令牌,则创建一个包含更多数据的新自定义令牌,然后 return 将此新自定义令牌发送给客户端
- 让客户端 re-authenticate 使用新的自定义令牌,并使用它与 Firebase 以及我们的其他 API 项目(主要在 .NET Core 中)进行通信
步骤 1-3 工作正常。 尝试在其他服务上验证自定义令牌时出现问题。
TL;DR : 这里有两个问题:
- 验证使用 Firebase Node.JS Admin SDK 发出的自定义令牌时,我应该使用什么作为 public 密钥?从 Google 公开的 JWK 中提取的密钥,或从用于签名的私钥中提取的密钥?
- 如果是 JWK 方法,我应该如何使用
kid
header 构造自定义令牌?
首先,我对验证它的正确方法存有疑问。 (请原谅,我没有创建 OAuth 流程的经验。)使用的算法是 RS256,所以我应该能够使用 public 密钥验证令牌。据我所知,有两种方法可以获取此密钥:
- 从私钥中提取 public 密钥并使用它进行验证。我可以这样做并在我的身份验证服务器上的测试端点上成功验证,但是我觉得这是不正确的方法
- 另一种我认为更正确的方法是使用令牌中的值在我的项目的 Google 的“/.well-known/openid-configuration/”端点上找到 JWK, , 即
https://securetoken.google.com/[项目 ID]/.well-known/openid-configuration
检索正确 kid
(密钥 ID)的指数和模数并从中创建 public 密钥。
admin SDK通过
生成的token
admin.auth().createCustomToken(uid, additionalClaims).then(function(customToken)
一些自定义声明看起来像这样:
headers:
{
"alg": "RS256",
"typ": "JWT"
}
有效负载:
{
"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"
}
不过,我似乎无法使用方法 2。一个问题是 生成的令牌没有 kid
header,因此不符合 OpenID规范(AFAIK),这导致两个选项之一:
- 使用上面的第一种方法。但这会导致问题 - 如果我出于某种原因需要撤销或重置身份验证服务器上的私钥,我需要这样做并将更改也部署到所有其他服务上,从而使解决方案的动态性降低并且更多 error-prone.
- 使用 jwt.io 中提到的库之一手动生成类似的令牌,并将原始 Firebase ID 令牌中的孩子添加到它的 headers。
数字 2 有问题:
- 那iss、aud、sub应该放什么?与管理 SDK 的值相同吗?如果是这样,那不是'cheating',因为他们不再是发行人了吗?
- 我已经试过了(生成一个类似的令牌副本,但添加了原始令牌的
kid
),但我似乎无法使用为以下创建的 PEM 密钥验证生成的令牌孩子.
我做后者的方式是这样的(遵循关于这个主题的blog guide):
转到 https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com 并检索相关孩子的模数 (n) 和指数 (e)
使用库生成 public 密钥 (rsa-pem-from-mod-exp)
使用密钥验证使用the 'official' jwt lib
上面的结果是 public 键:
-----开始 RSA PUBLIC 密钥-----
MIIBCgKCAQEAxXpo7ChLMnv1QTovmm9DkAnYgINO1WFBWGAVRt93ajftPpVNcxMT
MAQI4Jf06OxFCQib94GyHxKDNOYiweVrHVYH9j/STF+xbQwiPF/8L7+haC2WXMl2
tkTgmslVewWuYwpfm4CoQFV29OVGWCqwEcbCaycWVddm1ykdryXzNTqfzCyrSZdZ
k0yoE0Q1GDcuUl/6tjH1gAfzN6c8wPvI2YDhc5gIHm04BcLVVMBXnC0hxgjbJbN4
zg2QafiUpICZzonOUbK6+rrIFGfHpcv8mWG1Awsu5qs33aFu1Qx/4LdMAuEsvX9f
EmFZCUS8+trilqJbcsd/AQ9eOZLAB0BdKwIDAQAB
-----结束 RSA PUBLIC 密钥-----
有两点似乎不对。一是密钥与我从私钥中提取的密钥不同。另一个是我从私钥中提取的那个有这些注释:
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
没有 'RSA'。这有关系吗?无论如何,它不验证。
终于,我是不是完全误解了OpenID流程? JWK 是否是从我需要的私钥生成的,以验证我的 JWT?我应该暴露我的在我的身份验证服务器上拥有 JWK,以便其他服务联系和使用而不是 Google?我对 Firebase Admin SDK 能做什么和不能做什么感到有点困惑,我想 :-)
我知道有很多问题,但我认为它们都是相关的。
我在研究中依赖的一些资源(当然除了官方的 admin sdk 文档):
使用自定义令牌重新验证 Firebase 客户端 SDK 后,客户端实际上生成了一个新的 ID 令牌,其中包含来自自定义令牌的声明。您应该使用此 ID 令牌来验证对不同微服务发出的请求(已记录 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()
以在您需要时获取有效的 ID 令牌。该方法代表您处理所有缓存。
我正在做一个项目,我们将在微服务架构中使用不同的服务,我们还想使用一些 Firebase 服务。我正在开发一个身份验证服务器,该服务器将创建自定义 JWT 以用于 Firebase 以及其他 API 项目。
我们想使用 Firebase Auth SDK 轻松与 FB、Google、Twitter 等集成,但我们需要用更多数据丰富用户的令牌。因此,我的想法是创建一个 Node.JS 身份验证服务器,它使用 Firebase Admin SDK 来执行此操作。流程如下:
- 用户在客户端使用最喜欢的提供商登录
- 如果登录成功,用户会收到来自 Firebase 的 JWT。这被发送到 auth 服务器进行验证
- 如果授权服务器可以使用管理 SDK 验证令牌,则创建一个包含更多数据的新自定义令牌,然后 return 将此新自定义令牌发送给客户端
- 让客户端 re-authenticate 使用新的自定义令牌,并使用它与 Firebase 以及我们的其他 API 项目(主要在 .NET Core 中)进行通信
步骤 1-3 工作正常。 尝试在其他服务上验证自定义令牌时出现问题。
TL;DR : 这里有两个问题:
- 验证使用 Firebase Node.JS Admin SDK 发出的自定义令牌时,我应该使用什么作为 public 密钥?从 Google 公开的 JWK 中提取的密钥,或从用于签名的私钥中提取的密钥?
- 如果是 JWK 方法,我应该如何使用
kid
header 构造自定义令牌?
首先,我对验证它的正确方法存有疑问。 (请原谅,我没有创建 OAuth 流程的经验。)使用的算法是 RS256,所以我应该能够使用 public 密钥验证令牌。据我所知,有两种方法可以获取此密钥:
- 从私钥中提取 public 密钥并使用它进行验证。我可以这样做并在我的身份验证服务器上的测试端点上成功验证,但是我觉得这是不正确的方法
- 另一种我认为更正确的方法是使用令牌中的值在我的项目的 Google 的“/.well-known/openid-configuration/”端点上找到 JWK, , 即
https://securetoken.google.com/[项目 ID]/.well-known/openid-configuration
检索正确 kid
(密钥 ID)的指数和模数并从中创建 public 密钥。
admin SDK通过
生成的tokenadmin.auth().createCustomToken(uid, additionalClaims).then(function(customToken)
一些自定义声明看起来像这样:
headers:
{
"alg": "RS256",
"typ": "JWT"
}
有效负载:
{
"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"
}
不过,我似乎无法使用方法 2。一个问题是 生成的令牌没有 kid
header,因此不符合 OpenID规范(AFAIK),这导致两个选项之一:
- 使用上面的第一种方法。但这会导致问题 - 如果我出于某种原因需要撤销或重置身份验证服务器上的私钥,我需要这样做并将更改也部署到所有其他服务上,从而使解决方案的动态性降低并且更多 error-prone.
- 使用 jwt.io 中提到的库之一手动生成类似的令牌,并将原始 Firebase ID 令牌中的孩子添加到它的 headers。
数字 2 有问题:
- 那iss、aud、sub应该放什么?与管理 SDK 的值相同吗?如果是这样,那不是'cheating',因为他们不再是发行人了吗?
- 我已经试过了(生成一个类似的令牌副本,但添加了原始令牌的
kid
),但我似乎无法使用为以下创建的 PEM 密钥验证生成的令牌孩子.
我做后者的方式是这样的(遵循关于这个主题的blog guide):
转到 https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com 并检索相关孩子的模数 (n) 和指数 (e)
使用库生成 public 密钥 (rsa-pem-from-mod-exp)
使用密钥验证使用the 'official' jwt lib
上面的结果是 public 键:
-----开始 RSA PUBLIC 密钥----- MIIBCgKCAQEAxXpo7ChLMnv1QTovmm9DkAnYgINO1WFBWGAVRt93ajftPpVNcxMT MAQI4Jf06OxFCQib94GyHxKDNOYiweVrHVYH9j/STF+xbQwiPF/8L7+haC2WXMl2 tkTgmslVewWuYwpfm4CoQFV29OVGWCqwEcbCaycWVddm1ykdryXzNTqfzCyrSZdZ k0yoE0Q1GDcuUl/6tjH1gAfzN6c8wPvI2YDhc5gIHm04BcLVVMBXnC0hxgjbJbN4 zg2QafiUpICZzonOUbK6+rrIFGfHpcv8mWG1Awsu5qs33aFu1Qx/4LdMAuEsvX9f EmFZCUS8+trilqJbcsd/AQ9eOZLAB0BdKwIDAQAB -----结束 RSA PUBLIC 密钥-----
有两点似乎不对。一是密钥与我从私钥中提取的密钥不同。另一个是我从私钥中提取的那个有这些注释:
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
没有 'RSA'。这有关系吗?无论如何,它不验证。
终于,我是不是完全误解了OpenID流程? JWK 是否是从我需要的私钥生成的,以验证我的 JWT?我应该暴露我的在我的身份验证服务器上拥有 JWK,以便其他服务联系和使用而不是 Google?我对 Firebase Admin SDK 能做什么和不能做什么感到有点困惑,我想 :-)
我知道有很多问题,但我认为它们都是相关的。
我在研究中依赖的一些资源(当然除了官方的 admin sdk 文档):
使用自定义令牌重新验证 Firebase 客户端 SDK 后,客户端实际上生成了一个新的 ID 令牌,其中包含来自自定义令牌的声明。您应该使用此 ID 令牌来验证对不同微服务发出的请求(已记录 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()
以在您需要时获取有效的 ID 令牌。该方法代表您处理所有缓存。