You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用jwt-php及Firebase令牌生成器的HS256令牌签名无效问题

解决Firebase自定义令牌invalid_custom_token与签名验证失败问题

我之前也碰到过几乎一模一样的Firebase自定义令牌坑,结合你说的「修改UID或displayName任意字符就能验证通过」这个细节,大概率是字段隐形字符/编码问题或者签名密钥处理错误导致的,下面给你一步步排查和解决的思路:

1. 先排查UID和displayName的字符问题

你提到改一个字符就能过,这十有八九是这两个字段里藏了不可见的控制字符(比如全角空格、换行符、零宽空格),或者编码不是标准UTF-8。这些字符肉眼看不到,但会让JWT的payload哈希值变化,导致签名不匹配。

建议生成令牌前强制清洗字段:

// 去除首尾空白(包括隐形控制字符)
$cleanUid = trim($yourOriginalUid);
$cleanDisplayName = trim($yourOriginalDisplayName);

// 强制转成UTF-8编码
if (mb_detect_encoding($cleanUid) !== 'UTF-8') {
    $cleanUid = mb_convert_encoding($cleanUid, 'UTF-8');
}
if (mb_detect_encoding($cleanDisplayName) !== 'UTF-8') {
    $cleanDisplayName = mb_convert_encoding($cleanDisplayName, 'UTF-8');
}

用清洗后的字段重新生成令牌,先去jwt.io验证,大概率能解决签名问题。

2. 检查签名密钥的正确性

firebase-token-generator-php依赖服务账户的私钥,很多人复制密钥时会不小心带多余字符(比如JSON里的换行、空格,或者复制时多了首尾引号),导致签名算法无法正确计算哈希。

可以试试用jwt-php手动生成令牌对比:

use Firebase\JWT\JWT;

// 确保私钥是完整读取的,不要手动复制粘贴
$privateKey = file_get_contents('path/to/your-service-account-private-key.pem');

$payload = [
    'iss' => 'your-service-account-email@your-project.iam.gserviceaccount.com',
    'sub' => 'your-service-account-email@your-project.iam.gserviceaccount.com',
    'aud' => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
    'uid' => $cleanUid,
    'displayName' => $cleanDisplayName,
    'iat' => time(),
    'exp' => time() + 3600, // 有效期设1小时
    'admin' => false
];

$token = JWT::encode($payload, $privateKey, 'RS256');

如果这个手动生成的令牌能在jwt.io验证通过,说明原来的firebase-token-generator-php库可能存在字段编码处理的bug(毕竟这个库已经好几年没更新了)。

3. 替换成官方推荐的生成方式

firebase-token-generator-php属于非官方维护的旧库,和最新版本的jwt-php兼容性很差。建议直接使用Firebase Admin SDK for PHP来生成自定义令牌,它会自动处理所有编码、签名细节,避免手动踩坑:

use Firebase\Admin\Auth\Auth;
use Firebase\Admin\FirebaseAdmin;

// 初始化Admin SDK
$firebase = FirebaseAdmin::initialize([
    'credentials' => 'path/to/service-account.json'
]);

$auth = $firebase->getAuth();
// 生成自定义令牌
$customToken = $auth->createCustomToken($cleanUid, ['displayName' => $cleanDisplayName]);

用官方SDK生成的令牌基本不会出现签名问题,而且后续维护也有保障。

4. 最后确认Payload的必填字段

确保你的JWT Payload里这几个字段完全正确:

  • iss和sub必须是你的服务账户邮箱
  • aud必须是固定值:https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit
  • exp(过期时间)不能超过当前时间+3600秒(1小时)

内容的提问来源于stack exchange,提问作者11teenth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:36:31