Authorizarion on json-server with a JWT

Viewed 2206

I am trying to make a node app which is using typicode json-server, I want to add authorization to the app, where GET request is open to all public, but PUT, POST & DELETE request require a JWT token and only then they can proceed on the api.

I have tried to make a small app, but I am not able to figure out the next part of authorization and how to use middlewares on node, as I am a frontend developer.

Here is the app that I have written.

    const jsonServer = require('json-server')
    const app = jsonServer.create()
    const router = jsonServer.router('db.json')
    const middlewares = jsonServer.defaults()
    const morgan = require('morgan');
    const jwt = require('jsonwebtoken');
    const config = require('./config');
    const bodyParser = require('body-parser');

    app.set('Secret', config.secret);
    app.use(morgan('dev'));
    app.use(bodyParser.urlencoded({ extended: true }));
    app.use(bodyParser.json());

    app.use(middlewares)
    app.use((req, res, next) => {
        if (req.method === 'GET') {
            console.log(req);
            next();
        } else {
            if (req.path === '/login') {
                getToken(req, res);
            }
            if (isAuthorized(req, res)) {
                console.log("I am here");
                next();
            } else {
                console.log("I am in error");
                res.sendStatus(401)
            }
        }
    })
    app.use(router)
    app.listen(3000, () => {
        console.log('JSON Server is running on 3000')
    })

    function isAuthorized(req, res) {

        console.log("sadasdasdasd");

        var token = req.headers['access-token'];
        console.log(token);
        // decode token
        if (token) {
            console.log("Inside token");
            jwt.verify(token, app.get('Secret'), (err, decoded) => {
                console.log("Inside JWT fn");
                if (err) {
                    console.log("Inside JWT fn err");
                    return res.json({ message: 'invalid token' });
                } else {
                    console.log("Inside JWT fn success");
                    req.decoded = decoded;
                    return true;
                }
            });

        } else {
            // if there is no token  
            res.send({
                message: 'No token provided.'
            });
        }
    }

    function getToken(req, res) {
        if (req.body.username === "test") {
            if (req.body.password === 123) {
                const payload = {
                    check: true
                };
                var token = jwt.sign(payload, app.get('Secret'), {
                    expiresIn: 1440 // expires in 24 hours
                });
                res.json({
                    message: 'Authentication Successful ',
                    token: token
                });
            } else {
                res.json({
                    error: 'Invalid Password',
                });
            }
        } else {
            res.json({
                error: 'Please provide valid credentials',
            });
        }
    } 

1 Answers

You are doing in right way. But, have some issue in your isAuthorized middleware. In the middleware you have a asynchronous action (jwt.verify), then you can not use this function as a "helper function" as the official document of json-server (the function return boolean value).

Make isAuthorized become a middleware and you it like a middleware:

function isAuthorized(req, res, next) { // Pass 3 parmas to a express middleware 

  console.log("sadasdasdasd");

  var token = req.headers['access-token'];
  console.log(token);
  // decode token
  if (token) {
    console.log("Inside token");
    jwt.verify(token, app.get('Secret'), (err, decoded) => {
      console.log("Inside JWT fn");
      if (err) {
        console.log("Inside JWT fn err");
        return res
          .status(401) // I think will be better if you throw http status is 401 to client
          .json({ message: 'invalid token' });
      } else {
        console.log("Inside JWT fn success");
        req.decoded = decoded;
        return next(); // Only call "next" if everything is good, continue next jobs - handle secured requests
      }
    });

  } else {
    // if there is no token  
    return res
    .status(401)
    .send({
      message: 'No token provided.'
    });
  }
}

Use the middleware

    app.use((req, res, next) => {
        if (req.method === 'GET') {
            console.log(req);
            next();
        } else {
            if (req.path === '/login') {
                getToken(req, res);
            }
            isAuthorized(req, res, next); // Here
        }
    })
Related