Journey to the real world by cloning DEV.to backend server(part 5)
Tags: node, apollo, express, prisma
Published: 2021-05-14 02:38:56

> In the last post we have created our first model user model and started our development server.
In this post we will work on jwt authentication using jsonwebtoken package.



## Authentication workflow in our platform

when users will visit our platform first time they do not have any token so they will be unauthenticated and unauthorized.

> In Simple term UnAuthenticated user means they have not loggedin in our platform and UnAuthorized means they may or may not be login but definitely not  allowed for specific pieces of actions.
For example: In our Platform any one can read posts no required for login but to create post they must have to login. If someone is moderator then it have some specific role for that. Normal reader cannot make an action which are specially designed for moderators.

When user will login then from backed they will get a jwt token. Then from next request they will provide that jwt token in Authentication header and backend will decode that and recognise who is the user in this token.

We knew that HTTP is stateless they have no idea how to manage user session because our backend is on localhost:4000 nodejs server and frontend may be on localhost:3000  React  client it will not possible for http to remember user. 
Hence we have a way to handle this kind of problems

We will generate a jwt token for every loggedin user and will send to him they will put this token in localstorage and for further request they will send the token inside http headers.

> JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

You can found more about jwt [here](https://jwt.io/).

### Setup schema and resolvers for authentication

create some directory to chunk our logic in different file and folder


1. create `graphql` dir in `src/` dir
2. create `util` dir in `src/` dir
3. create dir `typeDefs` in `graphql` dir
4. create dir `resolvers` in `graphql` dir
5. create file `index.js` in `typeDefs` dir
6. create file `index.js` in `reslovers` dir
7. create file `auth.util.js` in `util` dir

> when we will proceed in this series then we will see how we will break schema and resolvers in multiple file with ease

`devblog_server/src/typeDefs/index.js`

This file will contain all the query, mutation and subscription .

For authentication we will use `jsonwebtoken` and for password hashing we will use `bcrypt` library which is freely available in npm

```
pnpm add jsonwebtoken bcrypt

```

Lets create authentication query and mutation

`src/graphql/typeDefs/index.js`


```javascript
const { gql } = require("apollo-server-express");

module.exports = gql`
  type AuthResponse {
    token: String!
    user: User!
  }

   type Mutation {
    login(email: String!, password: String): AuthResponse!
    register(name: String!, email: String!, password: String!): AuthResponse!
  }
`;



```

And now create add resolvers for above query 

`src/graphql/resolvers/index.js`


```javascript
const { UserInputError, AuthenticationError } = require("apollo-server-errors");
const {
  generateHash,
  generateUsername,
  matchPassword,
  generateJwtToken,
} = require("../../utils/auth.util");

module.exports = {
  
  Mutation: {
    // login user
    async login(_, { email, password }, { prisma }) {
      try {
        const user = await prisma.user.findUnique({
          where: {
            email,
          },
        });

        if (!user) {
          throw new UserInputError("USER_NOT_FOUND", {
            message: "Account with this email does not found create new one",
          });
        }

        const matchPass = await matchPassword(password, user.password);

        if (!matchPass) {
          throw new UserInputError("INCORRECT_PASSWORD", {
            message: "Password is incorrect",
          });
        }

        const token = generateJwtToken(user.id);

        return {
          user,
          token,
        };
      } catch (error) {
        return error;
      }
    },

    // create new account
    async register(_, { name, email, password }, { prisma }) {
      try {
        const checkEmail = await prisma.user.findUnique({
          where: {
            email,
          },
        });

        if (checkEmail) {
          throw new UserInputError("EMAIL_ALREADY_EXISTS", {
            message: "Account with this email is already exists ",
          });
        }

        username = generateUsername(email);
        password = await generateHash(password);

        const newUser = await prisma.user.create({
          data: {
            name,
            email,
            password,
            username,
          },
        });

        const token = generateJwtToken(newUser.id);

        return {
          token,
          user: newUser,
        };
      } catch (error) {
        return error;
      }
    },
  },
};

```


above we have implemented registration and login for users when we will proceed in series i will show you how easily we will create admin user from environment variable.


`src/util/auth.util.js`

```javascript
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
exports.generateUsername = (email) => {
  const max = 9990;
  const min = 1000;

  return (
    email.split("@")[0] + Math.floor(Math.random() * (max - min))
  );
};

exports.generateHash = async (password) => {
  const hash = await bcrypt.hash(password, 10);
  return hash;
};

exports.matchPassword = async (password, hashPassword) => {
  const hasMatch = await bcrypt.compare(password, hashPassword);
  return hasMatch;
};

exports.generateJwtToken = (userId) => {
  return jwt.sign({ userId }, process.env.JWT_SECRET, { expiresIn: "10h" });
};


exports.decodeJwtToken = (token) => {
  const {userId}  = jwt.verify(token,process.env.JWT_SECRET)
  return userId
}
```

This is utility file which contain utility function related to authentication.


Last thing to do is update `src/server.js` by typeDefs and resolvers.

`server.js`

```javascript
....
const typeDefs = require("./graphql/typeDefs");
const resolvers = require("./graphql/resolvers");

....


```

Save all the stuff and go to graphql playground at `localhost:4000/graphql` and start hacking around authentication


register query

```
mutation {
  register(name:"Harsh Mangalam",email:"harshdev@dev.com",password:"123456"){
    token
   user {
    id
    name
    username
    createdAt
    role
    
  } 
  }
}

```


This will give you result like this

```
{
  "data": {
    "register": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEwLCJpYXQiOjE2MjA5NTk1MjQsImV4cCI6MTYyMDk5NTUyNH0.xmdJYVpZUxcUhr5CBQwR1C7yLjKSEvAmjt7gr2sjsNw",
      "user": {
        "id": "10",
        "name": "Harsh Mangalam",
        "username": "harshdev5301",
        "createdAt": "1620959524586",
        "role": "USER"
      }
    }
  }
}

```


login query

```
mutation {
  login(email:"harshdev@dev.com",password:"123456"){
    token
   user {
    id
    name
    username
    createdAt
    role
    
  } 
  }
}
```



login query result

```
{
  "data": {
    "login": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEwLCJpYXQiOjE2MjA5NTk2MjcsImV4cCI6MTYyMDk5NTYyN30.59OHuy3L5F_0Oes-3kYQwNcsl9vJnTXx-63h0aiVHvc",
      "user": {
        "id": "10",
        "name": "Harsh Mangalam",
        "username": "harshdev5301",
        "createdAt": "1620959524586",
        "role": "USER"
      }
    }
  }
}

```

> In our next post we will break our graphql schema and resolvers into chunk so that development will easier and we will work more on user and profile sections.