DEV Community

Cover image for Authentication Best Practices: Building a Robust Authentication System
Vartika Sharma
Vartika Sharma

Posted on

Authentication Best Practices: Building a Robust Authentication System

Adding authentication to an application is one of the most challenging but also a very important part for developers. Today, I will teach you how to create an authentication page in just 10 minutes.

First, let's initialize npm and install all the necessary packages that we are going to use. Open your terminal and run the following commands:

npm init -y
npm i express bcryptjs body-parser dotenv ejs jsonwebtoken mongoose cookie-parser
Enter fullscreen mode Exit fullscreen mode

Next, create two directories named "views" and "public". Inside the "views" directory, create three files: "signin.ejs", "signup.ejs", and "home.ejs". Your folder structure should look like this:

- views
  - signin.ejs
  - signup.ejs
  - home.ejs
- public
- server.js
Enter fullscreen mode Exit fullscreen mode

Now, let's include the necessary packages and configure our express server in the "server.js" file:

const express = require('express');
const bodyparser = require("body-parser");
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const port = process.env.PORT || 3000;
const app = express();
require('dotenv').config();
const bcrypt = require('bcryptjs');
const salt = 10;

app.set('view engine', 'ejs');
app.use(bodyparser.urlencoded({ extended: true }));
app.use(express.json());
app.use(cookieParser());
app.use(express.static("public"));

app.listen(port, () => {
  console.log(`Running on port ${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Next, let's create our user schema for authentication and implement the signup functionality:

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

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

app.post('/signup', async (req, res) => {
  const { email, password: plainTextPassword } = req.body;
  const password = await bcrypt.hash(plainTextPassword, salt);

  try {
    const response = await User.create({
      email,
      password
    });

    return res.redirect('/');
  } catch (error) {
    console.log(JSON.stringify(error));

    if (error.code === 11000) {
      return res.send({ status: 'error', error: 'email already exists' });
    }

    throw error;
  }
});
Enter fullscreen mode Exit fullscreen mode

Now, let's implement the login functionality using JWT to create an authentication token:

const verifyUserLogin = async (email, password) => {
  try {
    const user = await User.findOne({ email }).lean();

    if (!user) {
      return { status: 'error', error: 'user not found' };
    }

    if (await bcrypt.compare(password, user.password)) {
      const token = jwt.sign({ id: user._id, username: user.email, type: 'user' }, process.env.JWT_SECRET, { expiresIn: '2h' });
      return { status: 'ok', data: token };
    }

    return { status: 'error', error: 'invalid password' };
  } catch (error) {
    console.log(error);
    return { status: 'error', error: 'timed out' };
  }
};

app.post('/login', async (req, res) => {
  const { email, password } = req.body;

  const response = await verifyUserLogin(email, password);

  if (response.status === 'ok') {
    res.cookie('token', response.data, { maxAge: 2 * 60 * 60 * 1000, httpOnly: true });
    res.redirect('/');
  } else {
    res.json(response);
  }
});
Enter fullscreen mode Exit fullscreen mode

Finally, let's create a route for the protected page and check for authentication before accessing it:

const verifyToken = (token) => {
  try {
    const verify = jwt.verify(token, process.env.JWT_SECRET);

    if (verify.type === 'user') {
      return true;
    } else {
      return false;
    }
  } catch (error) {
    console.log(JSON.stringify(error), "error");
    return false;
  }
};

app.get('/', (req, res) => {
  const { token } = req.cookies;

  if (verifyToken(token)) {
    return res.render('home');
  } else {
    res.redirect('/login');
  }
});

app.get('/login', (req, res) => {
  res.render('signin');
});

app.get('/signup', (req, res) => {
  res.render('signup');
});
Enter fullscreen mode Exit fullscreen mode

That's it! You have successfully added authentication to your application. Now you can create a login and signup page, and protect your routes using JWT authentication.

Don't forget to create a .env file to store your secret key for JWT and MongoDB connection URL.

I hope this tutorial was helpful. Happy coding!

Connect With Me

I hope you found this guide helpful. If you have any questions, feedback, or just want to connect and discuss more about web development and security, feel free to reach out.

Looking forward to connecting with fellow tech enthusiasts and professionals!

Top comments (0)