Authentication and Authorization in Node.js
Tags: javascript, node, jwt, express
Published: 2024-02-11 17:37:50

Authentication and authorization are really important for websites. They make sure that the people using the site are who they say they are, and that they can only do things they're supposed to do. In this blog, we'll explain what these terms mean and show you how to use them in a Node.js website.

## Authentication vs. Authorization
Before diving into implementation details, let's clarify the distinction between authentication and authorization:

- **Authentication:** It is like showing your ID to prove who you are. It's the process of making sure that the person using a website is really the person they say they are, by checking things like their username and password.

- **Authorization:** Once a user is authenticated, authorization determines what actions they are allowed to perform within the application. It defines access permissions based on the user's identity and role.

## Implementing Authentication and Authorization in Node.js
To demonstrate authentication and authorization in Node.js, we'll use the popular `express` framework along with `jsonwebtoken` for generating and verifying JSON Web Tokens (JWT).

###Step 1: Setting Up the Node.js Project
First, let's initialize a new Node.js project and install the necessary dependencies:

```bash
mkdir node-authentication-authorization
cd node-authentication-authorization
npm init -y
npm install express jsonwebtoken bcrypt
```
###Step 2: Creating the Authentication System
We'll create routes for user registration, login, and profile access. We'll also generate JWTs for authenticated users.

```javascript
// index.js
const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

const app = express();
app.use(express.json());

// Dummy user database
const users = [];

// Register a new user
app.post('/register', async (req, res) => {
    try {
        const hashedPassword = await bcrypt.hash(req.body.password, 10);
        const user = { username: req.body.username, password: hashedPassword };
        users.push(user);
        res.status(201).send("User registered successfully.");
    } catch {
        res.status(500).send("Error registering user.");
    }
});

// Login
app.post('/login', async (req, res) => {
    const user = users.find(user => user.username === req.body.username);
    if (user == null) {
        return res.status(400).send("User not found.");
    }
    try {
        if (await bcrypt.compare(req.body.password, user.password)) {
            const accessToken = jwt.sign(user, process.env.ACCESS_TOKEN_SECRET);
            res.json({ accessToken: accessToken });
        } else {
            res.status(401).send("Incorrect password.");
        }
    } catch {
        res.status(500).send("Error logging in.");
    }
});

// Profile route
app.get('/profile', authenticateToken, (req, res) => {
    res.json(req.user);
});

// Middleware to authenticate token
function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];
    if (token == null) return res.sendStatus(401);
  
    jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
        if (err) return res.sendStatus(403);
        req.user = user;
        next();
    });
}

app.listen(3000, () => {
    console.log('Server started on http://localhost:3000');
});

```

###Step 3: Protecting Routes with Authorization
We'll implement a simple authorization mechanism to restrict access to certain routes based on user roles.

```javascript
// index.js

// Define user roles
const roles = {
    admin: 'admin',
    user: 'user'
};

// Example protected route accessible only by admin
app.get('/admin', authenticateToken, (req, res) => {
    if (req.user.role !== roles.admin) return res.status(403).send("Forbidden");
    res.send("Admin panel");
});
```

###Step 4: Testing the Authentication and Authorization
You can test the authentication and authorization endpoints using tools like Postman or by making HTTP requests using curl.

```bash
# Register a new user
curl -X POST -H "Content-Type: application/json" -d '{"username":"user1", "password":"password123"}' http://localhost:3000/register

# Login
curl -X POST -H "Content-Type: application/json" -d '{"username":"user1", "password":"password123"}' http://localhost:3000/login

# Access profile with obtained access token
curl -H "Authorization: Bearer <ACCESS_TOKEN>" http://localhost:3000/profile

# Access admin route (assuming admin role)
curl -H "Authorization: Bearer <ACCESS_TOKEN>" http://localhost:3000/admin

```
##Conclusion
In this guide, we've looked at how to make sure the right people can access your web app securely. We talked about two important ideas: authentication (making sure users are who they say they are) and authorization (giving them the right permissions). I showed you how to set this up in a Node.js app using something called JSON Web Tokens. By following these steps, you can make sure your web app keeps sensitive information safe and gives users a good experience.