Hello,
I use Auth0 for authentication, and I have a client configured to use RS256 to sign my jwts. My use case is simply generating mock jwts for testing. I see that if I were using HMAC, I could simply pass my client secret to the sign method. However, I do not see how I can generate a mock token with RS256 that can pass my jwt check middleware that uses the auth0/express-jwt library.
Here is my middleware jwt verification:
authenticate.jwtCheck = jwt({
// Dynamically provide a signing key based on the kid in the
// header and the singing keys provided by the JWKS endpoint.
secret: jwksRsa.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: 'https://bar.auth0.com/.well-known/jwks.json',
}),
// Validate the audience and the issuer.
audience: 'foo',
issuer: 'https://bar.auth0.com/',
algorithms: ['RS256'],
});
Thanks!
I will repeat it to see if I understood correctly:
If that's the case I can think on 2 solutions:
a) You can use nock, when the jwksUri is called in testing execution you will control the response to return the certificate you use for testing.
b) You have the jwksUri and the issuer in a config file, for testing you load testing url + issuer, you would need to be able to access to that testing url to load your testing certificate.
Didn't occur to me to use nock to mock the jwksUri, that should work perfectly. Thanks!
Hello,
I have similar question. I need to sign tokens for tests with RS256. As i cant get the private key from auth0, i'm trying to generate RSA private key to sign tokens and i have to make JWK from my private key for decoding middleware. I have tried npm module pem-jwk, but unsuccessfully.
小ould you please tell me, where I'm wrong?
Thanks.
Hi @alexander-velichko , you need to sign the tokens with the private key (as you do) and provide a jwk using the public key. I've not used pem-jwk but I think it could work.
@ziluvatar I'm sorry for disturbing.
I generate key pair with openssl:
To sign token I do that:
const jwt = require('jsonwebtoken');
const cert = fs.readFileSync('private.pem');
function(authId) {
return jwt.sign({
sub: authId
}, cert, {
algorithm: 'RS256',
audience: clientID, (from auth0 config)
issuer: issuer
});
};
Then i convert public.pem to jwk with pem-jwk like that:
const { pem2jwk, jwk2pem } = require('pem-jwk');
const str = fs.readFileSync('./public.pem');
const jwk = pem2jwk(str);
And the problem is that generated jwk very different from auth0 jwk:
generated:
{ kty: 'RSA',
n: 'wzG33UI26k6fb4t6swAlnQ07mX3kTAcF8z8Y3ApRCZSxaK07d7bMGrHcKix2q4O8e4GVmJYPe7mTwSCvHF2kJ0g8yvzLvHde6B-ao1Tub6LAnZcccVxy62tzvP7hQVDfBre2irZ1JSpU5Zu38EQtJrqzKWIxLfunAlwubvt1Q2CuT-EzMkbwHm3NN8Hs0FZ8Qf3L0-Rc4C2fhklDWjzYBDm96ZxX-wMpJw91-TGN2xWz92S5sjPiMKM23LRlv6rYKSAMo5k1JaPwfWaS8fzct9feXBpaf3XC4wB_7ZHsSCjVwGprMlDypLk1p9jka1m5at4Kta1I4xr0kVxMZ_l6Gw',
e: 'AQAB',
d: 'ooiEzHV1WrdrJSukWObXayX4qb_dWL1EZB73KUph3jN1Ym9VJEMPQ280n910Vy8TxFfL5EmXzPNjKB56EYmbxaXuESxczassWObwEe8Ht-dysgaBBZfwjT1lG0u073lSrLpPAsQZWYAdPy_iAuwSGLy_sMb1oo94qottkrZKF3Y2M9GGoj7pQoe4FcqT6TEjuGGnUYB_a5-Kw3MF4n2QOjBgJT-Wvj_bfh4UwoNkODNnIyBGh-4kv6OTJqfzl5PJgaTZrIiCCmMP-cHJz5HSnZvCQIV00qvMaWfVcqeeNay6FikEeyCvLb2cMg5u-mfiKX0J0IVgpx2gl2tFFwTOgQ',
p: '6S4SXOD3R0u7JN_AuZGLBF8zW4uAh4EDwN1rxmKgJ_U3xlfgKVs4lvahg_o2Sn3xlofxlBTwu2wrx3JCLTMe9uHBWWUH0uz7u5JgJpr4c5IrO4Ud-NNU7W6kvkyQaEzE9xGY6GEzZ71VY-D_4RYevsvSt8MWyTkUaqldQVng9ME',
q: '1kv6VM5JAUu5f8NW52jSjDIyJZ9jUVzSpnzt02iMj5jc_9UGp2mN40G_F9iUQthT0BhEjS33dO6jamUsQF3c9hFgwhI_-JPRxe5q-tAPRRRmW9yQo3qiRD1MIrR7s5dJSBffCFSipIxeaS4Xi7NIm9gw0tNK26VJQxkW85axWds',
dp: 'xL4awEMQYReEz5f7BJfIs-efbZ5G1A4HHLO2O6z7dLtyU-fROxO8q6Nso-554GBjdp89NbR1aa3bQm0laP25IpVYjhSwhUdvHtRiTDB1cQ3jbFTk9Q1amvrABdCUB2y-w7gVS_y3YtBdO-ib_U6sok9Xe7UfhKikkVpVVM6BAAE',
dq: 'VH5AhY-QWWJyEV4DtdouqfhgrVTa5AmlRN-dJe3i_ftXp8dmiDumJiSWI-DRFEoXQcVPwhqNpx0wcZLSj85ygNL5Q4vOjUQ7Qb9vjtTaMHKKqU2d-dcwg5dnnYdr_rN3wWUoGzDDr_1ofDAgOITH7CqhlX6Z1WCmMj6CPij8ZGE',
qi: 'Xq_KZFVl9FyzHnaSG7Xoh3WsNcPvno7yUgLIxUsOKsJfQgjN0r6sNZ44txWeE3EaEBAEp06kVcR93fhSG9UNU3A3L3rvcRGxIK89Jqr9PsjI_P80SNIvhXu6T7qHFkQFOpsd67r8HUDYZBnUo--i6EO4PZ22E8sWJDeVkZVjsXE' }
And i wrap it in this
{
keys: [ here is generated jwk]
}
example from auth0:
{
"keys": [
{
"alg": "RS256",
"kty": "RSA",
"use": "sig",
"x5c": [
"MIIC7jCCAdagAwIBAgIJSRMd8YG8+MK7MA0GCSqGSIb3DQEBBQUAMB4xHDAaBgNVBAMTE2VqdGVzdC5ldS5hdXRoMC5jb20wHhcNMTcwMjE3MDkyNDI3WhcNMzAxMDI3MDkyNDI3WjAeMRwwGgYDVQQDExNlanRlc3QuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwbAyQlT9Hzd55dNfTUB6dOCk/itdZpEagxNBERclJrLRjtbFapxndiTdNy0l1ah6cSY4Wx4wkgri5KlaqF1v237IecQYA+MgHG1adDaHCnkmQ4UM/4szFAm9TDDD5yXIjIX5fC16fOYrdQjl2vg1PqOminGRR6qbD/UEayungS1Ygd8ugSNoQ0MlQ7NIA9Q7biSKOsXPkEdLaTNSKmaaGWv4y+REuqlupwVe5DSTWKYV3JxPwZnCbugcxK4HsdW4qTgUPJRhArdEBLBfVTc89RkQw0+7VIdU4ycoY/PP56qIjY6Pj1qZpDM7oAUX11rnc6LkgEUcyy+NO7EIgF0JzwIDAQABoy8wLTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBS87+WyCnygwbJH48mj+UOdRHG4LDANBgkqhkiG9w0BAQUFAAOCAQEAHxmqofVhy8Qyybu2xQfAehpJh2F2ekV4CL3GkVggq0Ui3VaA6gQNF1kwP6EwBTeJKqLdDSQV6FbH9mUleb6DnJ/AcYydtsNd7gp0ruu0eECY/YM0ouSh1hvDM6gMdsSE+GMEYBx1ipo/2Hf9f4SYsNNHNGOinGOO2Wrdc+hducODL5OiemrokK9Oze65mBkQTXPNTNIONeKRaogeQ+/0bZmQLlVYhcJsRDJNHPdYQaPVqLj8hRo0+3063WqYIVJsNw90imIxJBCHDIpthxmqVM0Bq6oP7uVs9oZNZcftPYGoiAd/6rLHMH9dALW8CCniuC+d/G7CYKigBvp2Vnk4lw=="
],
"n": "wbAyQlT9Hzd55dNfTUB6dOCk_itdZpEagxNBERclJrLRjtbFapxndiTdNy0l1ah6cSY4Wx4wkgri5KlaqF1v237IecQYA-MgHG1adDaHCnkmQ4UM_4szFAm9TDDD5yXIjIX5fC16fOYrdQjl2vg1PqOminGRR6qbD_UEayungS1Ygd8ugSNoQ0MlQ7NIA9Q7biSKOsXPkEdLaTNSKmaaGWv4y-REuqlupwVe5DSTWKYV3JxPwZnCbugcxK4HsdW4qTgUPJRhArdEBLBfVTc89RkQw0-7VIdU4ycoY_PP56qIjY6Pj1qZpDM7oAUX11rnc6LkgEUcyy-NO7EIgF0Jzw",
"e": "AQAB",
"kid": "M0YyQjBBNzBCQjFCOUEyNzQ5QjBBRDJENzYyQjE3OERGOTVCMEM0RA",
"x5t": "M0YyQjBBNzBCQjFCOUEyNzQ5QjBBRDJENzYyQjE3OERGOTVCMEM0RA"
}
]
}
And jwt middleware gives error: JwksError: The JWKS endpoint did not contain any signing keys.
As i understand it, the problem lies in jwk. Do you have ideas? Appreciate any help.
Thanks!
@alexander-velichko I've got it working on my end, but with some different libraries than you are using.
Dependencies:
var jwt = require('jsonwebtoken');
var pem2jwk = require('pem-jwk').pem2jwk;
var keypair = require('keypair');
var nock = require('nock');
Code:
pair = keypair();
var publicJWK = pem2jwk(pair.public)
publicJWK.use = 'sig';
publicJWK.kid = 'put_any_string_here';
var jwkNock = nock('https://company.auth0.com/.well-known/jwks.json')
.get('')
.reply(200, {
keys: [publicJWK]
})
var token = jwt.sign({foo: 'bar'}, pair.private, {
algorithm: 'RS256',
header: {kid: 'put_same_string_here_matching_above_kid'},
audience: 'your_client_id',
issuer: 'your_url'
});
var req = {
headers: {
authorization: 'Bearer ' + token
}
}
expressJwtCheck(req, {}, (err) => {
// finish test
});
As you can see you just need to add the missing properties to the jwk. I would recommend inspecting the source code if you still have trouble, as you will be able to find where the error is being thrown and what you need to do to your jwk to make it work.
@RobinJayaswal
Thank you so much!
The problem was with kid and use properties of jwk.
I've done this:
1) Generated a private key using openssl genrsa -out private.pem 2048
2) I've used :
var pem2jwk = require('pem-jwk').pem2jwk;
var cert = fs.readFileSync(settings.rootPath + '/server/certs/private.pem');
var jwk = pem2jwk(cert)
console.log(jwk)
3) Copied the log from step 2) and created a certs.json (because looks loke this tool https://mkjwk.org/ is generating an imcomplete jwk)
4)
// cert is the jwk json created in step 3)
var cert = JSON.parse(fs.readFileSync(settings.rootPath + '/server/certs/certs.json'));
var jwkToPem = require('jwk-to-pem');
var scopes = userType;
privateJwk = jwkToPem(cert.keys[0], {
private: true
});
var token = jwt.sign({
id: user._id,
username: user.username,
scope: scopes
}, privateJwk, {
header: {
kid: settings.jwtKid
},
algorithm: 'RS256',
expiresIn: '4h'
});
token = {
user_code: user.user_code,
id_token: token
}
reply(token).code(200);
5) Created a route which returns the certs.json file
var certsPath = settings.rootPath + '/server/config/certs.json';
...
getCerts: {
handler: function(request, reply) {
return reply.file(certsPath)
.code(200);
},
tags: ['api'],
id: 'getCerts'
},
6) In order to validate the token
var jwksRsa = require('jwks-rsa');
...
server.auth.strategy('jwt', 'jwt', {
complete: true,
key: jwksRsa.hapiJwt2Key({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 2,
jwksUri: 'http://0.0.0.0:9000/user/jwk'
}),
validateFunc: verifyTokenFunc,
verifyOptions: {
algorithms: ['RS256']
}
});
Using Hapijs. It's working (the token is created and then validates ok) but it's a weird process. Is this correct? hope anyone use it :+1:
I think reimplementing this all the time is quite cumbersome, so I created this package. I would appreciate feedback / issues / some testing.
Most helpful comment
@alexander-velichko I've got it working on my end, but with some different libraries than you are using.
Dependencies:
Code:
As you can see you just need to add the missing properties to the jwk. I would recommend inspecting the source code if you still have trouble, as you will be able to find where the error is being thrown and what you need to do to your jwk to make it work.