DEV Community

Cover image for Creating An Auth System In NodeJS
Kinanee Samson
Kinanee Samson

Posted on • Edited on

Creating An Auth System In NodeJS

Authentication has become a Necessary part of most application, many a times you will build apps that require user authentication. The standard go to solution most developers use is to rely on a third party authentication system, like firebase, superbase this is not bad, I'd personally advice you to use one except you have a compelling reason not to. If however your reason is compelling enough then we are going to build a simple authentication system using NodeJS.

Dependencies

We need to spin up a new node project, create an empty folder and open it up in your editor, we will be using MongoDB and Mongoose to persist our user data so we will install the dependencies to handle that, first create a package.json file.

npm init --y
Enter fullscreen mode Exit fullscreen mode

Next we install Mongoose and other dependencies our application is going to rely on, let me give a brief list of the dependencies we will be installing;

to install all of the above dependencies run the following command

npm i bcrypt express cors jsonwebtoken

Enter fullscreen mode Exit fullscreen mode

To read more articles like this visit Netcreed

User Schema

Since we are working with Mongoose we need to create a user schema, a schema is just a logical structure that all object in a collection will conform to.

// UserSchema.ts

import { Schema } from "mongoose";

export const UserSchema = new Schema({
  fullName: {
    type: String
  },
  email: {
    type: String
  },
  password: {
    type: String
  }
}, {
  timestamps: true
})
Enter fullscreen mode Exit fullscreen mode

We have a basic schema to represent our user object. We just declare three properties for simplicity sake, I am not going to dive into Mongoose here, We are just concerned with the auth system, if you don't understand then it's best you visit the Mongoose documentation to familiarize yourself with the library. We will now proceed to our define our user model.

/// Users.ts

import { UserSchema } from "./UserSchema";
import * as bcrypt from "bcrypt";
import * as jwt from "jsonwebtoken";
import { model } from "mongoose";


function createJWT = (email: string) => {
  return jwt.sign(email, 'secrete', { expiresIn: 60*20 });
}


function verifyToken = (token: string) => {
  const email = jwt.verify(token, "secrete");
  if (email) {
    return email;
  }
}

UserSchema.statics.createAccount = async function (name: string, email: string, password: string) {
  const hashedPassword = await bcrypt.hash(password.trim(), 12);
  const user = await this.create({ 
    name: name.trim(), 
    email: email.toLowerCase().trim(), 
    password: hashedPassword
  });

  const token = createJWT(user.email);

  user.password = '';

  return [user, token];
}

UserSchema.statics.login = async function (email: stirng, password: string) {
  const user = await this.findOne({ email: email.toLowerCase() });

  if (!user) {
    throw Error("No user with that email");
  }

  const verifyPassword = await bcrypt.compare(password, user.password);

  if (!verifyPassword) {
    throw Error("Incorrect Password");
  };

  const token = createJWT(user.email);

  user.password = '';

  return [user, token];
}


UserSchema.statics.getUser = async function(token: string) {
  const email = verifyToken(token);
  if (email) {
    const user = await this.findOne({ email });
    return user;
  }
  return false;
}

export const Users = model("user", UserSchema);
Enter fullscreen mode Exit fullscreen mode

Now we have implemented the function for creating an account and to login the user, We declared them on the Schema so we could make our codebase easy to manage. We need to define controllers that will handle the request we will make to the server, on the controller we will register each function to a request route.

// controller.ts

import { Users } from "./Users";
import { Request, Response } from "express";

interface user {
  fullName: string
  email: string
  password: string
}

export const createAccount = async (req: Request, res: Response) => {
  const { fullName, email, password }: user = req.body;
  try {
    const [user, token] = await Users.createAccount(fullName, email, password);
    res.json({ user, token })
  } catch (error: any) {
    res.status(500).json({ message: error.message });
  }
}

export const login = async (req: Request, res: Response) => {
  const { email, password }: Pick<user, "email" | "password"> = req.body;
  try {
    const [user, token] = await Users.login(email, password);
    res.json({ user, token });
  } catch (error: any) {
    if (error.message.includes("Incorrect Password") ||
    error.message.includes("No user with that email")) {
      res.status(404).json({ message: error.message });
    }
    res.status(500).json({ message: error.message });
  }
}

export const getCurrentUser = async (req: Request, res: Response) => {
  const { token } = req.params;
  try {
    const user = await Users.getUser(token);
    if (user) {
      res.json({ user });
    }
  } catch (error: any) {
    res.status(500).json({ message: error.message });
  }
}
Enter fullscreen mode Exit fullscreen mode

We have defined some controller functions that will process user requests, we now register each controller function to a route, the controller function will serve as the route handler.

// router.ts
import { Router } from "express";
import { createAccount, login, getCurrentUser } from "./controller";

const router = Router();

router.post('/login', login);
router.post('/create-account', createAccount);
router.get('/current-user/:token', getCurrentUser);

export default router
Enter fullscreen mode Exit fullscreen mode

Everything is all set and done, all we need to do now is create our server and register this route as a middleware.

// app.ts

import * as express from "express";
import * as cors from "cors";
import * as router from './router';

const app = express();

app.use(cors());
app.use(router);

const url = 'mongodb://localhost:27017/plastic';

mongoose.connect(url).then((d: any) => {
  app.listen(PORT, () => console.log(`App running on PORT ${PORT}`));
})

app.get('/', (req:any, res:any) => {
  res.end('Hello World!');
})
Enter fullscreen mode Exit fullscreen mode

To read more articles like this visit Netcreed

Top comments (0)