验证 Auth0 JWT 抛出无效算法

Verifying Auth0 JWT throws invalid algorigthm

我已经创建了一个 Auth0 客户端,我正在登录并收到此令牌:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1rVkdOa1l5T1VaQ1JqTkRSVE5EUmtNeU5rVkROMEUyUTBVMFJrVXdPVEZEUkVVNU5UQXpOZyJ9.eyJpc3MiOiJodHRwczovL3RvdGFsY29tbW56LmF1LmF1dGgwLmNvbS8iLCJzdWIiOiJnb29nbGUtb2F1dGgyfDEwMzI5NzA4OTYyMTk5NjUwMjY2MiIsImF1ZCI6ImxTWUtXMUZZdENkMWJLQmdXRWN0MWpCbmtDU3R2dW5SIiwiaWF0IjoxNTA5ODYyMTI1LCJleHAiOjE1MTAyMjIxMjV9.kjmckPxLJ4H9R11XiBBxSNZEvQFVEIgAY_jj2LBy4sEJozBB8ujGE7sq9vEIjMms-Lv2q9WzFQPrqcxyBcYC4Je4QojMgvqLDCodtpot0QUle8QfGmonc1vZYIZyX-wqyOXtRqhoZVEKTeLhm9Le2CV4_a3BwgjkE1LjcDx01GZfsnaId8mh10kGk-DBmr5aVc8MxglLCq5Uk8Zbl2vDc__UMDgx1eQPQg-zve4fUf8zHcxizypYTnF_v0dEAT00L2j5J41SFYdWvP6ReQ3vhVYew2o9iM6u1s75HE-xW8s4pzV4BZAQtgfgIeCd6aVGZs76bcnQXBLej1B7zaPBvA

我现在要做的是使用 jsonwebtoken 验证令牌。令牌使用 RS256 算法签名。

我将签名证书下载为 .pem,我 成功地 使用它来验证令牌,如下所示:

var cert = fs.readFileSync('certificate.pem');
jwt.verify(token, cert, {algorithm: 'RS256'}, (err, decoded) => {
  console.log(err)
  console.log(decoded)
});

我想做但不起作用的是使用秘密(在 Auth0 客户端设置中称为 Client Secret 并且是一个字符串)验证令牌。

jwt.verify(token, MYSECRET, {algorithm: 'RS256'}, (err, decoded) => {
  console.log(err)
  console.log(decoded)
});

此代码总是抛出错误:

{ JsonWebTokenError: invalid algorithm
    at Object.module.exports [as verify] (C:\code\aws\learn-authorizer\node_modules\jsonwebtoken\verify.js:90:17)
    at Object.<anonymous> (C:\code\aws\learn-authorizer\testme.js:25:5)
    at Module._compile (module.js:624:30)
    at Object.Module._extensions..js (module.js:635:10)
    at Module.load (module.js:545:32)
    at tryModuleLoad (module.js:508:12)
    at Function.Module._load (module.js:500:3)
    at Function.Module.runMain (module.js:665:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3 name: 'JsonWebTokenError', message: 'invalid algorithm' }

我的问题是:如何使用密钥而不是使用证书文件来验证 RS256 令牌? (我也尝试创建一个使用 HS256 算法的新客户端,但我得到了同样的错误)。

您是否尝试过将算法设置为 "HS256"?

根据 https://auth0.com/docs/api-auth/tutorials/verify-access-token#verify-the-signature

的 Auth0 文档
For HS256, the API's Signing Secret is used. You can find this information at your API's Settings. Note that the field is only displayed for APIs that use HS256.

For RS256, the tenant's JSON Web Key Set (JWKS) is used. Your tenant's JWKS is https://YOUR_AUTH0_DOMAIN/.well-known/jwks.json.

如果您使用 密钥,那么使用 RS256 将不起作用,因为它基于 private/public 密钥对。仅使用密钥通常表示 H256。在我的回答中,我假设你所说的 MYSECRET 只是 certificate.pem.

的内容

无论如何,我假设您的字符串必须包含

-----BEGIN RSA PRIVATE KEY-----

-----END RSA PRIVATE KEY-----

PUBLIC 而不是 PRIVATE.

您可以在 source 中看到它。您的错误消息中提到的行包含:

if (!~options.algorithms.indexOf(header.alg)) {
  return done(new JsonWebTokenError('invalid algorithm'));
}

options.algorithms定义为

if (!options.algorithms) {
  options.algorithms = ~secretOrPublicKey.toString().indexOf('BEGIN CERTIFICATE') ||
                       ~secretOrPublicKey.toString().indexOf('BEGIN PUBLIC KEY') ?
                        [ 'RS256','RS384','RS512','ES256','ES384','ES512' ] :
                       ~secretOrPublicKey.toString().indexOf('BEGIN RSA PUBLIC KEY') ?
                        [ 'RS256','RS384','RS512' ] :
                        [ 'HS256','HS384','HS512' ];

}

如果您在开始和结束时没有 RSA 东西,它将查找以下算法:'HS256','HS384','HS512'.

我以前没有用过JWT的RS256,但是我用过ssh,我知道它对有header很敏感。字符串的格式必须完全正确。

您需要将允许的 algorithms 指定为字符串数组,而不是 algorithm 字符串。

jwt.verify(token, MYSECRET, { algorithms: ['RS256'] });

您需要更改验证方法的第三个参数,即

{algorithm: 'RS256'} to ==>{algorithms: 'RS256'}

并确保为算法编写正确的名称,它会正常工作

我也卡在这上面了!!

问题:

  • 解码能够让我们了解 JWT
  • 但我们需要验证令牌的签名

steps 如下代码:

  1. 我们解码令牌(使用 jsonwebtoken
  2. 我们从令牌中获取域名
  3. 我们得到 JSON 文件,其中 well-known/jwks 使用此域
  4. JWKS 可以不止一个,我们从 JWKS 得到相同的密钥,它在我们解码的令牌头中
  5. 我们使用node-jose包调用验证签名
  6. 您可以通过 repo 在本地进行测试:https://github.com/AkberIqbal/auth0-jwt-verify-signature-javascript-nodejs

const verifyJWT = async (token, verifyURL) => {

    return new Promise(async (resolve, reject) => {
        const result = jwt.decode(token, { complete: true });

        const domainFromToken = result?.payload?.iss;

        const signatureUrl = verifyURL ? verifyURL : `${domainFromToken}.well-known/jwks.json`;

        const jwksResponse = await axios.get(signatureUrl);

        const jwks = jwksResponse?.data?.keys;
        console.log('# of JWKS:', jwks.length, ' -trying to find:', result?.header?.kid);

        const relevantKey = jwks.filter(jk => jk.kid === result?.header?.kid);
        console.log('relevantKey:', relevantKey);

        let key = await jose.JWK.asKey(relevantKey[0]);

        const joseResult =
            await jose.JWS
                .createVerify(key)
                .verify(token)
                .catch(exp => {
                    console.log('exp:', exp);
                    reject(exp);
                });

        if (joseResult && Object.keys(joseResult).length > 0) {
            console.log('Object.keys(joseResult):', Object.keys(joseResult));
            // console.log('joseResult:', joseResult);
            resolve('ok');
        }
    })
}