Unable to get decoded payload of JWT from auth0/express-jwt library - node.js

I'm trying to obtain the decoded JWT payload using the express-jwt from auth0 as a middleware in my expressjs application. For the token to be used for authentication, I have to use a custom async function to process the token first before providing it to express-jwt. I understand that I can write a custom function under the getToken parameter as documented in express-jwt as shown below, but it does not work with async function.
const jwt = require("express-jwt");
const checkJwt = jwt({
secret: 'hello world !',
algorithms: ['HS256'],
credentialsRequired: false,
getToken: function fromHeaderOrQuerystring (req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
}
});
module.exports = checkJwt;
To overcome this limitation, I included the jwt() as part of a larger middleware function that first process the token, and then providing it to jwt(). The unprocessed token is attached to my headers. My code structure is as follows:
const myMiddleware = async (req, res, next) => {
// Process Token First
const processedToken = await functionToProcessToken(req.headers.tokenLocation);
// Jwt Authentication
jwt({
secret: 'hello world !',
algorithms: ['HS256'],
credentialsRequired: false,
getToken: processedToken
});
next();
});
module.exports = myMiddleware;
While I'm able to authenticate my routes without any issue, I need to get the decoded JWT payload for further uses. By default, as written in the documentation, the decoded payload should have been attached to req.user, but when I try to console.log it, it shows undefined. I have also tried adding requestProperty but it does not work as well. The documentation for resultProperty is not very clear, so I could not get that to work too.
I very much appreciate if someone can point me towards right direction to help me achieve the expected outcome for my middleware. Thank you!

Related

ExpressGraphql JWT authentication, not working

For the past 2 weeks, I'm working on this solution but no success. Can anyone suggest to me where I'm going wrong? For authentication, I'm using express-graphql, express-jwt for authentication [backend-[node, express-graphql, express-jwt, graphql-tools], frontend-[React-hooks,graphql-hooks]]. Following I'm using for authentication
const authMiddleware = jwt({
secret: app.get("getsecretval"),
credentialsRequired: false,
getToken: function fromHeaderOrQuerystring(req) {
if (
req.headers.authorization &&
req.headers.authorization.split(" ")[0] === "Bearer"
) {
return req.headers.authorization.split(" ")[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
}
});
app.use(authMiddleware);
app.use(
"/graphqlAPIRoute",
bodyParser.json(),
authMiddleware,
ExpressGraphQLHTTP(req => ({
schema: Schema,
rootValue: global,
context: {
user: req.user
}
}))
);
// Schema - place above authMiddleware
This even works when authorization headers not present,i.e., in case if the app idle in logged-in state as the token is stored in local storage, and not passed in headers yet the server code executes and fetches the data. Which must not be the case and must throw authentication error. If I add jwt verify we are not able to log in as there are no headers.
I suppose the auth middleware is not working and where do I place the jwt-verify function as to verify the token. For Jwt verify token I'm using
const jwtverify = require('jsonwebtoken');
Coz in express-jwt I've found no such functionality
Can anyone please lemme know where I'm going wrong? Any help would be appreciated.
Would this not work?
index.js - code sequence matters
const authMiddleware = jwt({
secret: "place secret here either pass as env",
credentialsRequired: false,
)}
app.use(authMiddleware);
const context = async (req) => {
const { authorization: token } = req.headers;
return { token };
};
app.use(
"/graphqlAPIRoute",
bodyParser.json(),
authMiddleware,
ExpressGraphQLHTTP(req => ({
schema: Schema,
rootValue: global,
}))
context: () => context(req),
);

Identity Server 4 for NodeJS API

I'm trying to figure out how to do the identity server 4 authentication below using NodeJS - way out of my comfort zone here.
services.AddAuthentication(IdentityServerAuthenticationDefaults
.AuthenticationScheme)
.AddIdentityServerAuthentication(
options =>
{
options.Authority = "<authority-url>";
options.ApiName = "<api-url>";
});
I'm missing something in the flow here as the C# implementation isn't provided a secret or similar - so the token is probably verified via identity server? How would I verify the token using NodeJS if I don't have a 'secret' to verify it with?
I've stumbled on introspection endpoint - am I heading in the right direction?
I was able to solve this using the jwks -endpoint and it's public keys to verify tokens and then I also found a nice package that I used to prepare the middleware:
private issuer: string = process.env.idsrv;
auth = jwt({
secret: jwksClient.expressJwtSecret({
cache: true, // see https://github.com/auth0/node-jwks-rsa#caching,
cacheMaxAge: ms('24h'),
rateLimit: true, // see https://github.com/auth0/node-jwks-rsa#rate-limiting
jwksRequestsPerMinute: 100,
jwksUri: `${this.issuer}/.well-known/jwks`
}),
// validate the audience & issuer from received token vs JWKS endpoint
audience: `${this.issuer}/resources`,
issuer: this.issuer,
algorithms: ["RS256"]
});
The accepted question is right. but i wanted to fix some of it's trial errors.
you can easily (it took me 4 days) add authentication to your express api with ids4.
it's how its work:
creating a middleware:
const jwt = require("express-jwt"),
jwksClient = require("jwks-rsa");
const auth = jwt({
secret: jwksClient.expressJwtSecret({
cache: true, // see https://github.com/auth0/node-jwks-rsa#caching
rateLimit: true, // see https://github.com/auth0/node-jwks-rsa#rate-limiting
jwksRequestsPerMinute: 2,
jwksUri: `${issuer}/.well-known/openid-configuration/jwks`,
}),
audience: "api1.resource", // <---- its your api resource.
issuer: issuer, // <----- address of identityserver4.
algorithms: ["RS256"], //<----- its needed algorithm to handle secret.
});
The following auth middleware is like following code in .net:
services.AddAuthentication(IdentityServerAuthenticationDefaults
.AuthenticationScheme)
.AddIdentityServerAuthentication(
options =>
{
options.Authority = "<authority-url>";
options.ApiName = "<api-url>";
});
to secure a nodejs route you can use following example:
// this is the secured route by identityserver4
// the jwt module set the ids4 auth result in req.user object
// so you can use it to access logged in user claims and stuff.
// for example testing with client credentials it return some info about the jwt token sent to the /me endpoint.
app.get("/me", auth, (req, res) => {
const user = req.user;
debug("req.user: %O", user);
return res.json(user);
});
// this a unsecured route. so anyone can call this route without any restrictions.
app.get("/", (req, res) => {
return res.send("Hello");
});
It takes me so long to find how to secure nodejs or express with identityserver4 but it was as simple as it look like.
The code here is from the following identityserver4 community example with full ids4 and node api and javascript client and .net console client:
https://github.com/lyphtec/idsvr4-node-jwks
There is a good documentation about this example in its own github repository too.
You can download the node api and run it with yarn start or npm run start.
I tested it with client credentials flow and it worked like a charm.
Wish all of you luck.
If you want only to validate your token you can use the following package:
npm install token-introspection --save
This package is configured with endpoint and client credentials, and a function is returned.
Calling that function with token, and optional token_type_hint will return a Promise.
const tokenIntrospection = require('token-introspection')({
endpoint: 'https://example.com/introspect',
client_id: '<Client ID>',
client_secret: '<Client Secret>',
});
tokenIntrospection(token).then(console.log).catch(console.warn);
Example :
Here is a middleware to validate the token :
module.exports = (req, res, next) => {
const token = "wEvxS0y2TkvCjLpKP33oGTK0BcKUb6MHt1u3AeMu8h4"; // get your token from your request
const tokenIntrospection = require('token-introspection')({
endpoint: 'http://localhost:5000/connect/introspect',
client_id: 'api1',
client_secret: 'apisecret',
});
tokenIntrospection(token).then(result => {
console.log(result);
next();
}).catch(console.warn);
}
then you can use it as below :
const auth = require('./atuh')
app.get('/', auth, (req, res, next) => {
res.send("Hi");
})

NodeJS and Express -- How to mock token authentication middleware for testing?

I'm making an REST API that uses JWTs for authentication, but to test my endpoints I want to mock the middleware that verifys the JWTs.
I've defined a middleware for checking the token:
// middlewares/auth.js
nJwt = require('njwt');
nconf = require('nconf');
module.exports = {
verifyToken: function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
nJwt.verify(token, nconf.get("auth:secret"), function(err, verifiedJwt) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.userId = verifiedJwt.body.sub;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}
}
Then in my routers I can import and use this middleware on protected endpoints
// routes/someRoutes.js
var router = require('express').Router();
var verifyToken = require('../middlewares/auth').verifyToken;
router.use(verifyToken);
// define routes
Now I want to mock this middleware out so that I can test the endpoints without need a valid token. I've tried doing using chai/mocha/sinon but don't have much luck
// tests/someRoutes.js
var auth = require('../middlewares/auth');
var sinon = require('sinon');
describe('someRoute', function() {
var verifyTokenStub;
before(function (done) {
verifyTokenStub = sinon.stub(auth, 'verifyToken', function(req, res, next) {
req.userId='test-id';
next();
});
});
});
But this is still calling the original verifyToken method. Any help is much appreciated!
Change your middlewares/auth.js file check process.env.NODE_ENV.
Example:
// middlewares/auth.js
...
// decode token
if (token || process.env.NODE_ENV === 'test') {//Changes in this string
// verifies secret and checks exp
nJwt.verify(token, nconf.get("auth:secret"), function(err, verifiedJwt) {
...
If you use supertest or package with same functionality, the run mocha with environment variable - NODE_ENV=test mocha.
If testing your application with full run, then you should start it with environment variable - NODE_ENV=test npm start.
It's not mocking, but I hope it will help you.

How to set authorization headers with nodejs and express

I am setting up a site with nodejs, express, mongoose and swig template following this tutorial :
Authenticate a Node.js API with JSON Web Tokens
In this tutorial the author uses Postman to set the token in the header.
I have googled for days to find out how I can set the jwt token in the header of my site, but it is not working for me.
If you want the client to include the token in it's request headers, you can use a cookie parser with express. (HTML5 Web Storage is another option). About Cookies:
Express can set the response headers to tell the client "add the token to a cookie".
Once the client sets the cookie with the token, the token will be in the client's request headers for each request. Let's get to baking with a little
npm install cookie-parser
Sprinkle on some
var cookieParser = require('cookie-parser')
app.use(cookieParser())
Access and set a cookie:
app.use(function (req, res, next) {
var cookie = req.cookies.jwtToken;
if (!cookie) {
res.cookie('jwtToken', theJwtTokenValue, { maxAge: 900000, httpOnly: true });
} else {
console.log('let's check that this is a valid cookie');
// send cookie along to the validation functions...
}
next();
});
You will probably want to do these things with the cookies (or whatever method you go with in the end):
set the cookie to hold the token when a user is authenticated.
check the cookie header value before allowing access to protected
routes.
send back an unauthorized status if a user doesn't have their token
when they are trying to access api routes that require a token.
May help someone in future...
Storing token in cookie with httpOnly:true flag is pretty secure from XSS attack but it can be vulnerable to CSRF attack.
Adding custom request headers for all routes in express using a middleware might be a feasible solution like that:
var token;
//asign 'accessToken' to 'token' in app.post('/login')
token=accessToken;
app.all('*' , (req, res, next) => {
if (!token) {
console.log('token: undefined');
} else {
req.headers.authorization = 'Bearer ' + token;
}
next();
});
this will add authorization=Bearer <token> header in each and every get request coming from browser. Now verify token in each secure route by adding this middleware:
let in app.get('/dashboard')
const authenticateToken=(req, res, next)=>{
var authHeader=req.headers['authorization'];
var token=authHeader && authHeader.split(' ')[1];
if(token==null){
return res.sendStatus(401);
}
jwt.verify(token, process.env.JWT_ACCESS_TOKEN, (err, user)=>{
if(err){
return res.sendStatus(403);
}
req.user=user;
next();
})
}
//in app.get(...)
app.get('/dashboard', authenticateToken ,()=>{
//stuff for authorized user
})
In case if you defined app.post('/login') in another file then,
export addHeader middleware as under:
//var to access token outside app.post('/login') route
var token;
app.post('/login' , (req , res)=>{
//authenticate the user
//create token
const accessToken=jwt.sign(user, secretKey);
//assign 'accessToken' to 'token' var
token=accessToken
//redirect to secure route
res.redirect('dashboard');
}
//middleware to add in your 'index.js' or 'app.js' file.
//export it only if you define app.post('/login') in another file
exports.addHeader = (req, res, next) => {
if (!token) {
console.log('token: undefined');
} else {
req.headers.authorization = 'Bearer ' + token;
}
next();
}
In index.js or app.js
//import file in which app.post('/login') is defined. let it is defined in controller/auth
const authController=require('./controller/auth');
//to add custom header in all routes
app.all('*', authController.addHeader);

Having issues with JWT and express-JWT

I'm testing out express-jwt and jsonwebtokens. I've never used this before and would like some help!
I've got the basics setup done and I only have one protected route.
app.use('/api', expressJWT({secret: 'cat'}));
Unfortunatley, i'm not able to access '/api' because it gives me this error
UnauthorizedError: No authorization token was found
If I use POSTman and issue a GET request with the following header
Authorization -> Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImJhc2hpciIsImlhdCI6MTQ1MTQ0MjM4NywiZXhwIjoxNDUxNDQyNjg3fQ.CnaLvS_oCEy_mp_9MSAmTTylJqQMI2Qlq9V3emAmN3E
Everything works fine and I'm able to access the content in '/api'.
But my issue is in my express application, specifically when I try to redirect the user to a new protected route.
User logs in and I create a new jwt token and redirect the user to '/api'
router.post('/login', passport.authenticate('local'), function (req, res) {
myToken = jwt.sign({
username: req.body.username
}, 'cat', {expiresIn: 60*5});
res.redirect('/api');
});
In this route, I set the headers and render the page.
router.get('/api', function (req, res) {
res.render('index', {user: req.user});
});
Unfortunately, I get the following error
UnauthorizedError: No authorization token was found
My goal is to be able to redirect a user to a protected route.
From my understanding, since /api is a protected route, express-jwt should be setting my authorization headers. Even if I try to manually set my headers using a middleware I still get an error.
Any help is greatly appreciated!
Thanks!
try something like res.redirect('/api?token ' + myToken);
Then to receive query inputs change the expressJWT normal function with a custom function.
app.use('/api', expressJWT({
secret: 'cat',
credentialsRequired: false,
getToken: function fromHeaderOrQuerystring (req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
}
}));
This was mostly from reading the expressJWT docs and other stack answers.

Resources