Verifying Auth0 JWT throws invalid algorigthm
Asked Answered
L

6

17

I have created an Auth0 client, I am logging in and receive this token:

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

What I am trying to do now is to verify the token using jsonwebtoken. The token is signed with an RS256 algorithm.

I downloaded the signing certificate as a .pem and I am successfully using it to verify the token like this:

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

What I want to do and it doesn't work is verifying the token using the secret (which is called Client Secret in the Auth0 client settings and is a string).

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

This code always throws an error:

{ 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' }

My question is: how can I verify the RS256 token using the secret key as opposed to using the certificate file? (I also tried creating a new client which is using the HS256 algorithm, but I get the same error).

Labradorite answered 5/11, 2017 at 7:0 Comment(2)
Try Updating Your jwt module.Alrich
@AkshitGrover I use the latest version alreadyLabradorite
O
14

If you are using only a secret key then using RS256 won't work, as it's based on a private/public key pair. Using only a secret key usually indicates H256. In my answer I assume that what you call MYSECRET is just the content of certificate.pem.

Anyways, I would assume your string has to contain

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

and

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

or PUBLIC instead of PRIVATE.

You can see this in source. The lines mentioned in your error message contains:

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

and options.algorithms is defined as

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' ];

}

If you don't have the RSA things at the start and end it will look for the following algorithms: 'HS256','HS384','HS512'.

I haven't used RS256 with JWT before, but I have used it with ssh, and I know that it's very sensitive to having the header. The string has to be in the exactly correct format.

Overfill answered 5/11, 2017 at 11:51 Comment(1)
I want to stress the value of this sentence "...it's very sensitive to having the header. The string has to be in the exactly correct format." It is indeed extremely sensitive, it cost me a day of work.Grier
C
9

You need to specify the allowed algorithms as an Array of Strings, instead of an algorithm String.

jwt.verify(token, MYSECRET, { algorithms: ['RS256'] });
Corbet answered 29/4, 2019 at 23:51 Comment(0)
A
3

You need to change the third parameter of your verify method which is

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

and make sure you write the correct name for the algorithm, It will work fine

Astrodynamics answered 7/1, 2021 at 13:43 Comment(0)
C
2

Have you tried setting the algorithm to "HS256"?

According to the Auth0 docs at 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.
Cornwell answered 5/11, 2017 at 11:40 Comment(0)
R
0

I was stuck on this too !!

problem:

  • decode was able to give us visibility into the JWT
  • but we needed to verify the signature of the token

steps in the following code:

  1. we decode the token (using jsonwebtoken)
  2. we get the domain from token
  3. we get JSON file which has the well-known/jwks using this domain
  4. JWKS can be more than one, we get the same key from JWKS which is in our decoded token header
  5. we use node-jose package which calls verifies the signature
  6. you can test on your local via 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).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');
    }

    })
}
Reconstructionist answered 21/3, 2022 at 22:36 Comment(0)
T
0

hello maybe you are missing utf8 flag, this works on 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'})
Tragedienne answered 17/8, 2023 at 11:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.