API Authorization Using Node.js

In this article, we will learn API Authorization using Node.js.

Step 1: First of all create a simple REST API in Node.js and then install the following npm packages.

npm install cors body-parser jsonwebtoken bcrypt

cors:- It’s an express middleware for enabling Cross-Origin Resource Sharing requests. Just because of it, We can access the API in different applications.

body-parser:- Node.js request body parsing middleware which parses the incoming request body before your handlers, and makes it available under req.body property. In other words, it simplifies the incoming request.

jsonwebtoken:- A JSON web token (JWT) is JSON Object which is used to securely transfer information over the web(between two parties). It can be used for an authentication process. We will use this package to create token with the help of user primary data and secret or private key.

bcrypt:- This will be used to hash our passwords, as we cannot save them directly for security purposes.

const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
 
const app = express();
const port = process.env.PORT || 4000;
 
// enable CORS
app.use(cors());
// parse application/json
app.use(bodyParser.json());
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
 
// request handlers
app.get('/', (req, res) => {
  res.send('Welcome to thecodehubs! - ' + req.user.name);
});
 
app.listen(port, () => {
  console.log('Server started on: ' + port);
});

Step 2: Here we have created a method for getting a token.

UserSchema is our model for users. In this function, we will return the auth token created using the “jsonwebtoken” package. For that, we need a user id and secret key (mentioned in the .env file). Make sure don’t use password and other sensitive information in user details to create a token.

UserSchema.methods.getSignedJwtToken = function(){
    return jwt.sign({id: this._id}, process.env.JWT_SECRET,{
        expiresIn: process.env.JWT_EXPIRE
    })
}

=> This sendTokenResponse function we have to call in login and register API for getting token.

const sendTokenResponse = (user, statusCode, res) =>{
    const token = user.getSignedJwtToken(); 

    const options = {
        expires: new Date(
            Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000
        ),
        httpOnly: true
    }
    if(process.env.NODE_ENV === 'production'){
        options.secure = true
    }

    res.status(statusCode)
        .json({
            status: true,
            token: token
        })
};

=> This register function passes to the API route and get authenticated bypassing the login credentials. If the user gets authenticated successfully then we will create a token and return it back.

router.post('/register', register)
exports.register = async (req, res, next) =>{
    try{
        const {name, email, password, role} = req.body;

        const user = await User.create({
            name,
            email,
            password,
            role
        })
        sendTokenResponse(user, 200, res);

    }catch (err){
        next(err);
    }
}

Step 3: Create a middleware method for authorization.

=> Here we have created protect function for authorization, simply pass this function to our routes.

We use this protect method as middleware in our request. It is executed before the rest of the request block and with this, we can add it to other requests to verify the JSON web token.

router.get('/me', protect, getMe)
router.put('/updatedetails',protect, updateDetail)
router.put('/updatepassword',protect, updatePassword)
exports.protect = async (req, res, next) =>{
    let token;
    if(req.headers.authorization && req.headers.authorization.startsWith('Bearer')){
        token = req.headers.authorization.split(' ')[1];
    }
    if(!token){
        return next(new ErrorResponse("Not authorize to access this route", 401))
    }
    try{
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        req.user = await User.findById(decoded.id)
        next();

    }catch{
        return next(new ErrorResponse("Not authorize to access this route", 401))
    }
}

Step 4: Here we have used bcrypt for generating a hash password.

UserSchema.pre('save', async function(next){
    console.log(this.isModified('password'))
    if(!this.isModified('password')){
        next();
    }
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt)
})

Step 5: Here we use express-mongo-sanitize, xss-clean packages to improve authorization.

express-mongo-sanitize:- Searches for any keys in objects that begin with a $ sign or contain a. from req.body, req.query, or req.params and either removes such keys and data or replaces the prohibited characters with another allowed character.

=> middleware which sanitizes user-supplied data to prevent MongoDB Operator Injection.

xss-clean:- xss-clean Node.js Connect middleware to sanitize user input coming from POST body, GET queries, and url params. Works with Express, Restify, or any other Connect app.

This will sanitize any data in req.body, req.query, and req.params. You can also access the API directly if you don’t want to use as middleware.

//install following npm packages using (npm install express-mongo-sanitize helmet xss-clean)
const mongoSanitize = require('express-mongo-sanitize')
const xss = require('xss-clean');

app.use(mongoSanitize());
app.use(xss());

I hope this article helps you and you will like it.

Please give your valuable feedback and if you have any questions or issues about this article, please let me know.

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories