Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passport authentication with JWT: How can I change passport's default unauthorized response to my custom response?

I created a Node project with passport. When I did not give the token as header it returns Unauthorized. How can I change this message to pretty as Sorry invalid credentials

Every time when the token cannot be given I got the response as Unauthorized. I want to change this to pretty message.

passport.js

const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');

var User        = require('../models/user'); // get the mongoose model

const keys = require('../config/keys');

const opts = {};

opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;

module.exports = passport => {
    passport.use(
        new JwtStrategy(opts, (jwt_payload, done) => {
            User.findById(jwt_payload.id)
                .then(user => {
                    if (user) {
                        return done(null, user);
                    }
                    return done(null, false);
                })
                .catch(err => console.log(err))
        })
    );
};

user route.js

const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken');
const passport = require('passport');
const setting=require("../validation/settings");


const User = require('../models/user');


// *** GET *** /api/users/all *** Retrieve all users' basic details ***
router.get("/", passport.authenticate('jwt', {session: false}), function (req, res)
{
    var token = getToken(req.headers);
  console.log('the token: ' + token);

    User.find()
    .select('fname lname email avatar contact_no role')
    .where('is_deleted').equals('false')
    .exec()
    .then(docs => {
        return res.send(setting.status("User details retrieval successfully",false, "User details retrieval successfully", docs))
        //res.status(200).json(setting.status(validation.SHOW,true,"User details retrieval successfully.",docs))
    .catch(err => {
        return res.send(setting.status("Error in retrieving user details",false, "Error may token", err))
    });
    });
});


getToken = function (headers) {
  if (headers && headers.authorization) {
    var parted = headers.authorization.split(' ');
    if (parted.length === 2) {
      return parted[1];
    } else {
      return null;
    }
  } else {
    return null;
  }
};


module.exports = router;

How can I change the unauthorized message as pretty ("You cannot get the details,") ?

like image 268
test team Avatar asked Oct 16 '22 08:10

test team


1 Answers

As per the official documentation of Passport you may use custom callback function to handle the case of failed authorization and override the default message.

If you are developing REST API and then you would want to send out pretty JSON response something as below:

{
    "error": {
        "name": "JsonWebTokenError",
        "message": "invalid signature"
    },
    "message": "You cannot get the details. You are not authorized to access this protected resource",
    "statusCode": 401,
    "data": [],
    "success": false
}

I was using Passport JWT authentication to secure some of my routes and was applied the authMiddleware as below:

app/middlewares/authMiddleware.js

const express = require('express');
const router = express.Router();
const passport = require('passport');
const _ = require('lodash');

router.all('*', function (req, res, next) {
  passport.authenticate('jwt', { session: false }, function(err, user, info) {

    // If authentication failed, `user` will be set to false. If an exception occurred, `err` will be set.
    if (err || !user || _.isEmpty(user)) {
      // PASS THE ERROR OBJECT TO THE NEXT ROUTE i.e THE APP'S COMMON ERROR HANDLING MIDDLEWARE
      return next(info);
    } else {
      return next();
    }
  })(req, res, next);
});

module.exports = router;

app/routes/approutes.js

const authMiddleware = require('../middlewares/authMiddleware');

module.exports = function (app) {
  // secure the route by applying authentication middleware
  app.use('/users', authMiddleware);
  .....
  ...
  ..

  // ERROR-HANDLING MIDDLEWARE FOR SENDING ERROR RESPONSES TO MAINTAIN A CONSISTENT FORMAT
  app.use((err, req, res, next) => {
    let responseStatusCode = 500;
    let responseObj = {
      success: false,
      data: [],
      error: err,
      message: 'There was some internal server error',
    };

    // IF THERE WAS SOME ERROR THROWN BY PREVIOUS REQUEST
    if (!_.isNil(err)) {
      // IF THE ERROR IS REALTED TO JWT AUTHENTICATE, SET STATUS CODE TO 401 AND SET A CUSTOM MESSAGE FOR UNAUTHORIZED
      if (err.name === 'JsonWebTokenError') {
        responseStatusCode = 401;
        responseObj.message = 'You cannot get the details. You are not authorized to access this protected resource';
      }
    }

    if (!res.headersSent) {
      res.status(responseStatusCode).json(responseObj);
    }
  });
};
like image 108
Rahul Gupta Avatar answered Oct 20 '22 04:10

Rahul Gupta