Creating An Auth System In NodeJS
Tags: node, javascript, typescript
Published: 2023-01-04 07:49:36

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](https://firebase.google.com/), [superbase](https://supabase.com/) 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.

```bash
npm init --y
```

Next we install [Mongoose](https://mongoosejs.com/docs/) and other dependencies our application is going to rely on, let me give a brief list of the dependencies we will be installing;

- [Bcrypt](https://www.npmjs.com/package/bcryptjs) for hashing user password
- [Cors](https://www.npmjs.com/package/cors) for cross origin resourse sharing
- [Express](https://expressjs.com/) for http
- [jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken) for user authorization

to install all of the above dependencies run the following command

```typescript
npm i bcrypt express cors jsonwebtoken

```

To read more articles like this visit [Netcreed](https://blog.thenetcreed.com)

### 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.


```typescript
// UserSchema.ts

import { Schema } from "mongoose";

export const UserSchema = new Schema({
  fullName: {
    type: String
  },
  email: {
    type: String
  },
  password: {
    type: String
  }
}, {
  timestamps: true
})
```

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](https://mongoosejs.com/docs/) to familiarize yourself with the library. We will now proceed to our define our user model.

```typescript
/// 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);
```

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.

```typescript
// 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 });
  }
}
```

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.

```typescript
// 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
```

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

```typescript
// 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!');
})
```

To read more articles like this visit [Netcreed](https://blog.thenetcreed.com)