通过Firebase Auth Emulator的CreateCustomToken()在JWT令牌中具有“alg”:“none”,使其无法通过Firebase Admin SDK或自定义JWT Verifier进行验证

sxpgvts3  于 2023-05-01  发布在  其他
关注(0)|答案(1)|浏览(160)

上下文:

我正在使用Firebase Admin SDK的Node Cloud Function来创建自定义令牌(在本地测试时通过模拟器)。该令牌被发送到React应用程序,在那里它被消费并转换为IdToken。然后,该令牌被尝试用作GolangREST服务器的auth令牌,我尝试使用Firebase Admin SDK对其进行验证

问题:

出于一些超出我推理的奇怪原因,每当我试图通过本地认证仿真器在本地仿真云函数中生成自定义firebase令牌时,"alg"的头似乎总是"none"。在部署该函数时,情况并非如此。
令牌生成示例代码:admin.auth().createCustomToken(request.body.username...
下面的屏幕截图表示TokenId的解码内容(当您使用生成的令牌登录并从获得的用户调用.getIdToken()时会获得它)

这个特定的ID Token在有效载荷中缺少“kid”报头,使得它对Golang Admin SDK中的VerifyIDTokenAndCheckRevoked()毫无用处(已经尝试过)。
并且也将使用自定义JWT验证器无效,因为“alg”是none,并且默认情况下它是不允许的。(表示错误:token is unverifiable: 'none' signature type is not allowed)以下代码表示自定义验证器:

func (s *authService) VerifyToken(ctx context.Context, token string) (*CustomClaims, error) {
    var customClaims *CustomClaims

    parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
        // It doesn't work even with this validation commented...
        if val, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
            return nil, fmt.Errorf("> Wrong signing method: %v", token.Method.Alg())
        } else {
            if val.Alg() != "RS256" {
                return nil, fmt.Errorf("> Unexpected signing method: %v", val.Alg())
            }
        }

        // In order to be able to decode the token manually, we need to give the private key to the Parse function
        hmacSecret := []byte(os.Getenv("FIREBASE_CREDENTIALS_PRIVATE_KEY"))
        return hmacSecret, nil
    })
    if err != nil {
        if errors.Is(err, jwt.ErrTokenMalformed) {
            return nil, fmt.Errorf("> Malformed authentication: %s", err.Error())
        } else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
            return nil, fmt.Errorf("> Expired authentication token: %s", err.Error())
        } else {
            return nil, fmt.Errorf("> Something is wrong with the authentication: %s", err.Error())
        }
    }

    if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok && parsedToken.Valid {
        byteClaims, err := json.Marshal(claims)
        if err != nil {
            return nil, err
        }

        err = json.Unmarshal(byteClaims, customClaims)
        if err != nil {
            return nil, err
        }

        return customClaims, nil

    }
    
    return nil, fmt.Errorf("> Something is wrong with the authentication claims")
    

    /* Deprecated method due to custom token verification issue (no kid header) with Admin SDK*/
    // client, err := s.app.Auth(ctx)
    // if err != nil {
    //  return nil, err
    // }

    // authToken, err := client.VerifyIDTokenAndCheckRevoked(ctx, token)
    // if err != nil {
    //  return nil, err
    // }

}

是否有解决此阻塞的方法?

也许允许模拟器用正确的“alg”头来签署令牌,或者跳过自定义JWT验证器中的“alg”验证?
我看到过另一个类似的问题,但它没有解决方案:Firebase createCustomToken() returns an invalid token in local emulators

更新

尝试创建自己的JWT令牌生成实现,但没有成功。看起来我能够生成一个完全工作的令牌,但是每当我想获取IdToken(firebase真正认证的令牌)时,它会被转换为一个非工作令牌,其中包含“alg”:“none”。
例如,我已经确定我在我这边做的一切都是正确的,但是Firebase IdToken生成器是导致问题的原因。

gojuced7

gojuced71#

Firebase Auth Emulator不签署JWT令牌,这是设计使然。
参见: www.example.com
出于安全原因,身份验证模拟器会发出未签名的ID令牌,这些令牌仅被其他Firebase模拟器或Firebase Admin SDK(配置后)接受。
但您可以使用Admin SDK创建和验证令牌。
要使其与Admin SDK一起工作,您必须将模拟器主机的环境变量设置为模拟器url:

FIREBASE_AUTH_EMULATOR_HOST=127.0.0.1:9099

如果您从不同的主机/服务器使用Admin SDK模拟器,则必须在两端设置此变量以指向您的模拟器主机。

相关问题