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

firebase/php-jwt解码报$keyMaterial类型错误排查

问题根因

抛出$keyMaterial must be a string, resource, or OpenSSLAsymmetricKey错误的直接原因是传参非法,同时代码存在逻辑错误会导致后续验签失败:

  • 直接将包含多个证书的完整数组$pkeys传入Key类构造函数,该类只接受单个公钥字符串、OpenSSL资源或OpenSSLAsymmetricKey实例作为密钥材料,不接受数组类型参数
  • 谷歌接口返回的是X.509格式证书,不是直接可用的公钥字符串,即使传入单个证书内容不做解析,也会被判定为无效密钥材料
  • 逻辑错误:当前拉取的谷歌公钥用于验签谷歌自动生成的Firebase ID Token,和你自己持有的服务账号私钥不属于同一密钥对,哪怕密钥格式问题修复,用这个公钥验你自己签发的JWT也会报签名无效。
修复步骤
  • 拆分JWT结构,解码头部的kid字段,从公钥列表里匹配对应ID的单个证书,禁止传入整个公钥数组
  • 用openssl_pkey_get_public()函数解析X.509证书内容,得到合法的OpenSSLAsymmetricKey实例后再传入Key类
  • 修正验签逻辑:验自己签发的JWT时,使用和签发私钥配对的公钥;验Firebase官方生成的用户ID Token时,再使用当前拉取的谷歌公钥
  • 删除多余的手动引入JWT组件异常文件的代码,composer autoload已经实现自动加载,手动引入容易在版本更新时出现路径匹配错误。
修正后的验签代码

将原代码中if ($pKeys_raw) {块内的逻辑替换为以下内容:

$pkeys = json_decode($pKeys_raw, true);
// 解析JWT头部拿匹配的公钥ID
$tokenParts = explode('.', $token);
if (count($tokenParts) !== 3) {
    throw new \RuntimeException('Invalid JWT structure');
}
$header = json_decode(base64_decode(strtr($tokenParts[0], '-_', '+/')), true);
if (!isset($header['kid'], $pkeys[$header['kid']])) {
    throw new \RuntimeException('No matching public key found for current JWT');
}
// 从X.509证书解析出合法公钥
$cert = $pkeys[$header['kid']];
$publicKey = openssl_pkey_get_public($cert);
if (!$publicKey) {
    throw new \RuntimeException('Failed to parse public key from X.509 certificate');
}
// 执行验签解码
$decodejwt = JWT::decode($token, new Key($publicKey, 'RS256'));
$decoded_array = (array) $decodejwt;
echo "Decode:\n" . print_r($decoded_array, true) . "\n";

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:51:21