Journey to the real world by cloning DEV.to backend server(part 5)

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 …


This content originally appeared on DEV Community and was authored by Harsh Mangalam

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.

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

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

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

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.

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.


This content originally appeared on DEV Community and was authored by Harsh Mangalam


Print Share Comment Cite Upload Translate Updates
APA

Harsh Mangalam | Sciencx (2021-05-14T02:38:56+00:00) Journey to the real world by cloning DEV.to backend server(part 5). Retrieved from https://www.scien.cx/2021/05/14/journey-to-the-real-world-by-cloning-dev-to-backend-serverpart-5/

MLA
" » Journey to the real world by cloning DEV.to backend server(part 5)." Harsh Mangalam | Sciencx - Friday May 14, 2021, https://www.scien.cx/2021/05/14/journey-to-the-real-world-by-cloning-dev-to-backend-serverpart-5/
HARVARD
Harsh Mangalam | Sciencx Friday May 14, 2021 » Journey to the real world by cloning DEV.to backend server(part 5)., viewed ,<https://www.scien.cx/2021/05/14/journey-to-the-real-world-by-cloning-dev-to-backend-serverpart-5/>
VANCOUVER
Harsh Mangalam | Sciencx - » Journey to the real world by cloning DEV.to backend server(part 5). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/05/14/journey-to-the-real-world-by-cloning-dev-to-backend-serverpart-5/
CHICAGO
" » Journey to the real world by cloning DEV.to backend server(part 5)." Harsh Mangalam | Sciencx - Accessed . https://www.scien.cx/2021/05/14/journey-to-the-real-world-by-cloning-dev-to-backend-serverpart-5/
IEEE
" » Journey to the real world by cloning DEV.to backend server(part 5)." Harsh Mangalam | Sciencx [Online]. Available: https://www.scien.cx/2021/05/14/journey-to-the-real-world-by-cloning-dev-to-backend-serverpart-5/. [Accessed: ]
rf:citation
» Journey to the real world by cloning DEV.to backend server(part 5) | Harsh Mangalam | Sciencx | https://www.scien.cx/2021/05/14/journey-to-the-real-world-by-cloning-dev-to-backend-serverpart-5/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.