错误信息
token signature is invalid: key is of invalid type: ECDSA verify expects *ecdsa.PublicKey
也可能输出为
- token signature is invalid: key is of invalid type: HMAC verify expects []byte
- token signature is invalid: key is of invalid type: RSA verify expects *rsa.PublicKey
- key is of invalid type: ECDSA sign expects *ecdsa.PrivateKey
- key is of invalid type
v5 会给出所需的类型(“ECDSA verify expects *ecdsa.PublicKey”、“HMAC verify expects []byte”);v4 只打印“key is of invalid type”。由于 v5 把它归入 `ErrTokenSignatureInvalid`,乍一看像是签名验证失败。
golang-jwt/jwt (Go) — jwt.ErrInvalidKeyType
含义
你的 `Keyfunc` 返回的值(或者传给 `SignedString` 的密钥)的 Go 类型与令牌的算法不符。golang-jwt 会对密钥做类型断言:ES* 验证需要 `*ecdsa.PublicKey`,RS*/PS* 需要 `*rsa.PublicKey`,EdDSA 需要 `ed25519.PublicKey`,HS* 需要 `[]byte`;签名则需要对应的私钥。这里根本没有执行任何密码学运算——密钥还没有机会出错,它本身就是错误类型的对象。
原因
返回的是 PEM 字节,而不是解析后的密钥
常见返回从 `.pem` 文件读取的 `[]byte`,对 HMAC 有效,对非对称算法则不行。必须先把这些字节解析为 `*ecdsa.PublicKey` 或 `*rsa.PublicKey`。
验证时传入了私钥
常见需要 `*ecdsa.PublicKey` 的地方不接受 `*ecdsa.PrivateKey`。应返回 `&priv.PublicKey`——更好的做法是完全不让私钥进入验证方。
HMAC 密钥以 string 类型返回
常见对于 HS256,Keyfunc 必须返回 `[]byte`。`string`(例如来自 `os.Getenv` 的值)无法通过类型断言。
返回的是 JWK 结构体或 map,而不是密码学密钥
偶见从 JWKS 解码到结构体或 `map[string]any` 中的密钥并不是密码学密钥。需要先进行转换(例如使用 go-jose 的 `JSONWebKey.Key`,或者 keyfunc 库对 JWKS 的支持)。
修复方法
- 1.
将 PEM 一次性解析为具体类型的密钥
golang-jwt 为每种密钥类型都提供了辅助函数。在启动时解析,然后从 Keyfunc 返回具体类型的密钥。
go pub, err := jwt.ParseECPublicKeyFromPEM(pemBytes) // ES256/384/512 // rsaPub, err := jwt.ParseRSAPublicKeyFromPEM(pemBytes) // RS*/PS* // edPub, err := jwt.ParseEdPublicKeyFromPEM(pemBytes) // EdDSA if err != nil { log.Fatal(err) } token, err := jwt.Parse(raw, func(t *jwt.Token) (any, error) { return pub, nil }, jwt.WithValidMethods([]string{"ES256"})) - 2.
以 []byte 返回 HMAC 密钥
把密钥转换为字节,并用 `WithValidMethods` 把算法限定为该 HMAC 算法,使 `alg` 为非对称算法的令牌无法进入这条代码路径。
go secret := []byte(os.Getenv("JWT_HMAC_SECRET")) // []byte, not string token, err := jwt.Parse(raw, func(t *jwt.Token) (any, error) { return secret, nil }, jwt.WithValidMethods([]string{"HS256"}))