> For the complete documentation index, see [llms.txt](https://guvi.gitbook.io/fsd/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://guvi.gitbook.io/fsd/docs/module-8-nodejs/authentication.md).

# Authentication

#### Introduction

Authentication is a crucial part of web application security. It ensures that users are who they say they are, protecting both user data and system integrity. In this blog, we'll dive deep into implementing authentication in a Node.js application using the Express.js framework. We'll cover everything from setting up the project to implementing secure login and registration systems.

#### Table of Contents

1. Setting Up the Project
2. Creating the User Model
3. Setting Up Authentication Middleware
4. Implementing User Registration
5. Implementing User Login
6. Protecting Routes
7. Using JSON Web Tokens (JWT)
8. Logout and Token Invalidation
9. Best Practices and Security Tips

#### Setting Up the Project

**Step 1: Initialize the Project**

First, create a new directory for your project and navigate into it. Then, initialize a new Node.js project.

```bash
mkdir auth-tutorial
cd auth-tutorial
npm init -y
```

**Step 2: Install Dependencies**

Install the necessary dependencies, including Express, Mongoose (for MongoDB), bcrypt (for hashing passwords), and jsonwebtoken (for handling JWTs).

```bash
npm install express mongoose bcrypt jsonwebtoken body-parser
```

#### Creating the User Model

We'll use MongoDB to store user data, so let's set up a Mongoose model for our users.

**Step 1: Connect to MongoDB**

Create a file `db.js` to handle the database connection.

```js
// db.js
const mongoose = require('mongoose');

const connectDB = async () => {
  try {
    await mongoose.connect('mongodb://localhost:27017/authTutorial', {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    console.log('MongoDB connected');
  } catch (error) {
    console.error(error);
    process.exit(1);
  }
};

module.exports = connectDB;
```

**Step 2: Define the User Schema**

Create a file `models/User.js` to define the User schema.

```js
// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');

const userSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true,
  },
  password: {
    type: String,
    required: true,
  },
});

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

userSchema.methods.matchPassword = async function (password) {
  return await bcrypt.compare(password, this.password);
};

const User = mongoose.model('User', userSchema);

module.exports = User;
```

#### Setting Up Authentication Middleware

**Step 1: Middleware for Handling JSON Web Tokens**

Create a file `middleware/auth.js` to handle JWT verification.

```js
// middleware/auth.js
const jwt = require('jsonwebtoken');
const User = require('../models/User');

const 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 res.status(401).json({ message: 'Not authorized, no token' });
  }

  try {
    const decoded = jwt.verify(token, 'your_jwt_secret');
    req.user = await User.findById(decoded.id).select('-password');
    next();
  } catch (error) {
    console.error(error);
    res.status(401).json({ message: 'Not authorized, token failed' });
  }
};

module.exports = { protect };
```

#### Implementing User Registration

**Step 1: Registration Route**

Create a file `routes/auth.js` and set up the registration route.

```js
// routes/auth.js
const express = require('express');
const User = require('../models/User');
const jwt = require('jsonwebtoken');

const router = express.Router();

router.post('/register', async (req, res) => {
  const { username, password } = req.body;

  try {
    const user = await User.create({ username, password });

    const token = jwt.sign({ id: user._id }, 'your_jwt_secret', {
      expiresIn: '30d',
    });

    res.status(201).json({ token });
  } catch (error) {
    console.error(error);
    res.status(400).json({ message: 'User registration failed' });
  }
});

module.exports = router;
```

#### Implementing User Login

**Step 1: Login Route**

In `routes/auth.js`, add a route for logging in users.

```js
// routes/auth.js
router.post('/login', async (req, res) => {
  const { username, password } = req.body;

  try {
    const user = await User.findOne({ username });

    if (user && (await user.matchPassword(password))) {
      const token = jwt.sign({ id: user._id }, 'your_jwt_secret', {
        expiresIn: '30d',
      });
      res.json({ token });
    } else {
      res.status(401).json({ message: 'Invalid credentials' });
    }
  } catch (error) {
    console.error(error);
    res.status(400).json({ message: 'User login failed' });
  }
});
```

#### Protecting Routes

**Step 1: Secure a Route**

To protect a route, use the `protect` middleware. For example, create a protected route in `routes/protected.js`.

```js
// routes/protected.js
const express = require('express');
const { protect } = require('../middleware/auth');

const router = express.Router();

router.get('/profile', protect, (req, res) => {
  res.json({
    id: req.user._id,
    username: req.user.username,
  });
});

module.exports = router;
```

#### Using JSON Web Tokens (JWT)

JWTs are used to securely transmit information between parties as a JSON object. They are compact, readable, and digitally signed, using a secret or a public/private key pair.

**Step 1: Token Creation**

In the registration and login routes, we use `jwt.sign()` to create a token.

```js
const token = jwt.sign({ id: user._id }, 'your_jwt_secret', {
  expiresIn: '30d',
});
```

**Step 2: Token Verification**

In the `protect` middleware, we use `jwt.verify()` to verify the token.

```js
const decoded = jwt.verify(token, 'your_jwt_secret');
```

#### Logout and Token Invalidation

**Step 1: Implement Logout**

While JWTs are stateless and don't require server-side invalidation, you can implement a logout by handling it client-side or maintaining a blacklist of tokens.

#### Best Practices and Security Tips

1. **Store Secrets Securely**: Never hard-code your JWT secret in your source code. Use environment variables instead.
2. **Use HTTPS**: Always use HTTPS to protect tokens from being intercepted.
3. **Short-lived Tokens**: Use short-lived tokens and refresh them to minimize the risk if a token is compromised.
4. **Validate User Input**: Always validate and sanitize user input to prevent injection attacks.
5. **Secure Passwords**: Use bcrypt to hash passwords and never store plaintext passwords.

#### Conclusion

In this detailed guide, we've covered setting up a Node.js and Express.js project, creating a user model, implementing authentication middleware, and creating routes for user registration and login. By following these steps, you can implement a secure authentication system in your web application. Remember to follow best practices to keep your application and user data safe. Happy coding!
