验证 Auth0 JWT 抛出无效算法异常。

17

我创建了一个 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客户端设置中称为客户端密钥,是一个字符串)验证令牌,但无法实现。

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算法,但是我得到了相同的错误)。


尝试更新您的jwt模块。 - Akshit Grover
@AkshitGrover 我已经使用了最新版本。 - Roco CTZ
6个回答

14

如果你只使用一个密钥,则使用RS256将不起作用,因为它基于私钥/公钥对。仅使用密钥通常表示H256。在我的答案中,我假设你所谓的MYSECRET只是certificate.pem的内容。

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

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

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

使用PUBLIC而不是PRIVATE

您可以在源代码中查看。错误消息中提到的行包含以下内容:

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中使用过它,并且知道它对于具有标头非常敏感。该字符串必须完全正确地格式化。


我想强调这句话的价值:“……它对于有头部非常敏感。字符串必须以完全正确的格式呈现。”它确实非常敏感,让我浪费了一整天的工作时间。 - Leo

9

您需要将允许的算法指定为字符串数组,而不是单个算法字符串。

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

3

您需要更改 verify 方法的第三个参数,该参数为

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

确保您为算法编写正确的名称,它将正常工作。


2
你尝试过将算法设置为“HS256”吗?
根据Auth0文档中https://auth0.com/docs/api-auth/tutorials/verify-access-token#verify-the-signature的说明。
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.

0

我也遇到了同样的问题!!

问题

  • 解码能够让我们看到 JWT 的内容
  • 但是我们需要验证令牌的签名

以下代码中的步骤

  1. 我们解码令牌(使用 jsonwebtoken
  2. 我们从令牌中获取域名
  3. 我们获取包含该域名的 well-known/jwks 的 JSON 文件
  4. JWKS 可能有多个,我们从 JWKS 中获取与解码后的令牌头部相同的密钥
  5. 我们使用调用验证签名的 node-jose
  6. 您可以在本地测试,使用该存储库: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).catch((exp)=>{
        console.log('Error getting jwkResponse:', exp);
        reject(false)
    });

    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)[0];
    console.log('relevantKey:', relevantKey);

    const algoForImport = selectedKey.alg
    const publicKey = await jose.importJWK(relevantKey, algoForImport);

     const { payload, protectedHeader }  = await jose.jwtVerify(token, publicKey, {
            iss: 'issuer, get this from decoded token, or the issuer you expect',
        }).catch(exp => {
            console.log('exp:', exp);
            reject(exp);
        });

    if (payload && Object.keys(payload).length > 0) {
        console.log('Object.keys(payload):', Object.keys(payload));
        // uncomment to take a closer look
        // console.log('joseResult:', joseResult);
        resolve('ok');
    }

    })
}


0

你好,也许你缺少了 utf8 标志,在 jsonwebtoken 9 上可以正常工作

const fs = require('fs')
const jwt = require('jsonwebtoken')

const private_key = fs.readFileSync('secret/private.key', 'utf8')
const public_key = fs.readFileSync('secret/public.pem', 'utf8')

const token = jwt.sign({
    data: 'data'
}, private_key, { algorithm: 'RS256' })

const verified = jwt.verify(token, public_key, { algorithms: 'RS256'})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接