Create A Node JS Authentication API with JWT
Before starting Creating our API we should be familiar with node js and how Api works plus familiarity about JWT else this might not be a relevant post for you
Let’s Start from the scratch
Installing Node js
Check your terminal whether Node js is installed or not
And if all above is correct we can just dive into creating our authentication API
Now we’ll install some package’s
npm i express jsonwebtoken mongoose nodemon
Now go to your package.json file and add this in your script line
"scripts": {
"start":"nodemon run index"
},
Final Package json file
{
"name": "codespaces-blank",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start":"nodemon run index"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2",
"jsonwebtoken": "^9.0.0",
"mongoose": "^7.3.1",
"nodemon": "^2.0.22"
}
}
Also Make sure to create your atlas Account if using MongoDB (I prefer this)
You might see process.env.variable so you can just ignore that as this is what ill use to hide some private information of database :)
Project Structure
Creating a basic express server and connecting it to the database
const express=require('express')
const mongoose=require("mongoose")
const dotenv=require('dotenv').config()
const app=express()
app.use(express.json())
mongoose.connect(process.env.DB_URI,{useNewUrlParser:true,useUnifiedTopology:true}).then((r)=>{
console.log("Connected to DB")
}).catch((e)=>{
console.log(e)
})
app.listen(3000,()=>{
})
That’s just a basic Server with no routes and stuffs currently going on
Now let’s create our Model first that we are going to use to store data in db
const express=require("express")
const router=express.Router()
router.get("/",(req,res)=>{
res.json("i work fine")
})
router.post("/login",(req,res)=>{
})
router.post("/register",(req,res)=>{})
module.exports=router
A small basic outline how the routes will be later as well
We’ll come back later to routes after defining our model as all the remaining code will be done there
Now User.js -> which is user model for storing username and password that’s all XD
const mongoose=require("mongoose")
const UserSchema=new mongoose.Schema({
username:{
type:String,
required:true,
},
password:{
type:String,
required:true,
min:8,
},
})
module.exports=mongoose.model("User",UserSchema)
This is our basic model to store username and password (ps: we’ll hash the password later)
alright our base is done now let’s move to route (Now the important stuffs begin)
but before going to Route.js let’s make express to use all our route’s by importing Route that we created in index.js
const express=require('express')
const mongoose=require("mongoose")
const dotenv=require('dotenv').config()
const Routes=require("./routes/Route")
const app=express()
app.use(express.json())
app.use(Routes)
mongoose.connect(process.env.DB_URI,{useNewUrlParser:true,useUnifiedTopology:true}).then((r)=>{
console.log("Connected to DB")
}).catch((e)=>{
console.log(e)
})
app.listen(3000,()=>{
console.log("server running on port 3000")
})
Okay so after doing this we will be able to check our api at “http://localhost:3000/”
I am using github codespaces so my url may differ but your’s will be http://localhost:3000
If you don’t know what is postman you can find it on google or YouTube
Now let’s work first on our register route
First we need to install a package for hashing the password “bcrypt”
npm i bcrypt
First i’ll add the code then explain
router.post("/register",(req,res)=>{
const userexist=User.findOne({username:req.body.username})
if(userexist){
res.json("User already exists")
}
else{
const password=bcrypt.hash(req.body.password,10)
const user=new User({
username:req.body.username,
password:password
})
user.save().then((r)=>{
res.json(r)
}).catch((e)=>{
res.json(e)
})
}
})
so in the above route first we checked wheather is the user is already existing in our database , if he/she exist’s we will send a response saying user already exists
next if the user does not exist that means it’s a new user so we create a new user by requesting the value by “req.body.username” similarly for the password
but before inserting it into the database we need to hash the password so that user’s data is never at risk :) so now we use bcrypt package to hash the password by passing it salt gen of 10 (you can read the documentation of the bcypt library)
router.post("/register",async(req,res)=>{
const userexist=await User.findOne({username:req.body.username})
if(userexist){
res.json("User already exists")
}
else{
const password=await bcrypt.hash(req.body.password,10)
const user=new User({
username:req.body.username,
password:password
})ja
const userdata=await user.save()
res.send(userdata)
}
})
Now let’s make Login
thought making login is pretty easy without using jwt
First we’ll check the username is correct or not then we’ll check wheather the password is correct but wait the password was hashed how will we be able to check that password with the hash as the hash look’s very weird text you can see in the above image
Though we will use bcrypt.compare to compare the hash with the password
router.post("/login",async(req,res)=>{
const user=await User.findOne({username:req.body.username})
if(user){
const validpassword=await bcrypt.compare(req.body.password,user.password)
if(validpassword){
res.json("Logged in")
}
else{
res.json("Invalid password")
}
}
})
This is a simple login but without JWT
Now let’s implement JWT
first i’ll add the code here
const jwt=require("jsonwebtoken")
router.post("/login",async(req,res)=>{
const user=await User.findOne({username:req.body.username})
if(user){
const validpassword=await bcrypt.compare(req.body.password,user.password)
if (!validpassword){
res.json("Invalid password")
}
const token=await jwt.sign({username:user.username},"enteryoursecret")
res.cookie("jwt",token,{httpOnly:true,maxAge:24*60*60*1000})
res.json("Logged in")
}
})
first import the jwt then we will add a token and sign it with our username you can use _id which is mostly used for this example i’ve used username , then provide your secret key which one of the most important thing so please keep it secure , i’ve just added some random thing for you to understand , then we will save the cookie which lifespan kept is 1day
After logging in you can see the cookie section , there will be a cookie named jwt that’s your JWT
well the second cookie is our is jwt
we’ll ill show you something bonus to verify the token
router.get("/isauth",async(req,res)=>{
const cookie=await req.cookies.jwt
const claims=await jwt.verify(cookie,process.env.SECRET_JWT)
if(!claims) return res.json("not authenticated")
const user=await User.findOne({username:claims.username})
const {password,...data}=await user.toJSON()
res.json(data)
})
router.get("/logout",(req,res)=>{
res.cookie("jwt","",{maxAge:0})
res.json("Logged out")
})
For logging out and verifying the token
/isauth is for verifying token
Though ill end here , Thank you for reading this and congrats if you were able to implement JWT
Check the repo if you want to try out (check second branch for email verification)
will make more stuffs like this soon
:)