如何使用 Node-jose 验证 JWT 签名

How to verify a JWT signature using Node-jose

我正在尝试使用 node-jose 来验证我的 JWT 的签名。我知道秘密,但无法将此秘密转换为用于验证的 JWK。

这是一个示例,说明我如何尝试使用我的秘密创建我的密钥并验证我的令牌。这导致 Error: no key found.

let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXJpYWxfbnVtYmVyIjoiNWYxMGExNjMtMjk2OC00ZDZkLWIyZDgtOGQxNjQwMDNlMmQ0Iiwic2VxIjo1MTI4MTYsIm5hbWUiOiJOYW1lMSIsImlkIjo2NTQsImRlc2NyaXB0aW9uIjoiVGVzdCBEZWNvZGluZyJ9.ahLaTEhdgonxb8rfLG6NjcIg6rqbGzcHkwwFtvb9KTE"
let secret = "SuperSecretKey"
let props = {
    kid: "test-key",
    alg: "HS256",
    use: "sig",
    k: secret,
    kty: "oct"
}
let key;
jose.JWK.asKey(props).then(function(result) {key = result})
jose.JWS.createVerify(key).verify(token).then(function(result){console.log(result)})

我是否需要修改我的令牌以在某处包含 kid header?我是否根据该库的已知秘密正确生成了密钥?

您的代码存在三个问题。

  1. 由于承诺的异步性质,key 在承诺完成时(在 .then 部分)获得一个值,但这发生在下一行之后被调用。

    直接在行 jose.JWK.asKey(... 之后放置一个 console.log(key),您会看到结果是“未定义”。所以其实是没有钥匙的。

  2. JWK 中的 k 值被视为 Base64Url 编码的八位字节。签署令牌时,必须使用 k 的 base64url 解码值,但不能直接使用 k

  3. 秘密“SuperSecretKey”对于 node.jose 来说太短了。对于 HS256 算法,密钥长度必须为 256 位。 node.jose 与其他库相比,似乎相当严格。

要解决第一个问题,您可以嵌套调用(这很快就会变得难以阅读,或者使用如下所示的 async/await 语法:

var jose = require('node-jose')

async function tokenVerifyer() 
{
    let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXJpYWxfbnVtYmVyIjoiNWYxMGExNjMtMjk2OC00ZDZkLWIyZDgtOGQxNjQwMDNlMmQ0Iiwic2VxIjo1MTI4MTYsIm5hbWUiOiJOYW1lMSIsImlkIjo2NTQsImRlc2NyaXB0aW9uIjoiVGVzdCBEZWNvZGluZyJ9.KK9F14mwi8amhsPT7ppqp_yCYwwOGcHculKByNPlDB8"
    let secret = "SuperSecretKeyThatIsLongEnough!!" // A 32 character long secret to get 256 bits.
    let props = {
        kid: "test-key",
        alg: "HS256",
        use: "sig",
        k: "cynZGe3BenRNOV2AY__-hwxraC9CkBoBMUdaDHgj5bQ",
        //k : jose.util.base64url.encode(secret), // alternatively use above secret
        kty: "oct"
    }

    let key = await jose.JWK.asKey(props)

    let result = await jose.JWS.createVerify(key).verify(token)
} 

tokenVerifyer()

在上面的示例中,k 是在 https://mkjwk.org/ and the token was created with that key on https://jwt.io 上生成的密钥(检查 'secret base64 encoded')。或者,您可以使用自己的密钥,但必须确保它足够长。

Do I need to modify my token to include the kid header somewhere?

上面的小例子没有将 kid 放入令牌中。对于任何实际应用程序,您通常会将 kid 添加到令牌 header 中。您的密钥库可能有更多密钥或旋转密钥,kid有助于 select 正确的密钥。