Step 1- Setup Express JS project
- Create a new directory and install the node modules
$ makdir authentication
$ cd authentication
$ npm init -y
2. After that let's add Typescript to the project. we can do that by running the following command.
$ npm i -g typescript
$ npm i -D typescript
3. Add express to the project. we can do that by running the following command.
$ npm i express
$ npm i -D @types/express
4. Open project in visual studio code.Create new folder in project root directory, which name is src.Under src create file index.ts.
// index.ts
import express from 'express';
const app = express();
const PORT = 3000;
app.listen(PORT, ()=>{
console.log(`Running on Port ${PORT});
})
5. Now open terminal and run node project.
$ node ./src/index.ts
When you are run this command, this will giving error
Solve this problem create tsconfig.json. We can do by running following command.
$ npx tsc --init
5. Add some change in tsconfig.json
"rootDir":"./src",
"outDir":"./dist",
"noImplicitAny": true,
tsconfig.json
6. Generate dist folder in root directory. You can generate folder using following command.
$ npx tsc --build
7. Now try to run project using command
$ node ./dist/index.js
Congratulations, i are setup node js project successfully.
8. Add some change in package.json, which help us to real time run project without every time build project then run project for changes reflect.
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node dist/index.js",
"build": "rimraf dist && tsc",
"start:dev": "nodemon ./src/index.ts"
},
9. Install nodemon,
nodemon is a tool that helps develop Node.js based applications by automatically restarting the node application when file changes in the directory are detected.
nodemon does not require any additional changes to your code or method of development. nodemon is a replacement wrapper for node
. To use nodemon
, replace the word node
on the command line when executing your script. you can install node using following command.
$ npm i -D nodemon
10 . Now you can running using following command:
$ npm run start:dev
Step 2 - Setup Router in express application
- Setup an Express application with a router in index.ts. First create router folder in root directory, under router folder create index.ts for router.
// router/index.ts
import express from "express";
const router = express.Router();
export default (): express.Router => {}
2. import router/index.ts in startup index.ts.
import router from './router';
app.use('/api', router());
Step 3 - Setup database
for database, i am using mongoDB to store user detail. To connet mongoDB, I am using mongoose package. to install mongoose in node js application.
you can used following command
$ npm i mongoose
// we are using typeScript then we have to install dev dependence
$ npm i @types/mongoose
To connect mongoDB we have to implement some code in statup index.ts
// index.ts
import mongoose from 'mongoose';
const MONGO_URL:any = "mongodb://localhost:27017";
mongoose.Promise = Promise;
mongoose.connect(MONGO_URL);
mongoose.connection.on('error', (error: Error) => console.log(error));
Step 4 Add User Schema
Add user schema and model for a user document in MongoDB
Schema Fields:
- username: A required, unique String field for the user's username.
- email: A required, unique String field for the user's email.
- name: A required String field for the user's full name.
- password: A required String filed for the user's password.
- createdAt: A Date field with a default value of Date.now.
- updateAt: An optional Date field intended to track when the document was last updated.
import mongoose from "mongoose";
import bcrypt from 'bcryptjs';
const UserSchema = new mongoose.Schema({
username: { type: String, required: true, unique:true },
email: { type: String, required: true, unique:true },
name:{type:String, required:true},
password:{type:String, required:true},
createdAt: {
type: Date,
default: Date.now
},
updateAt:{
type:Date,
required:false
},
});
export const UserModel = mongoose.model("User", UserSchema);
export const getUserByEmail = (email: string) => UserModel.findOne({ email });
export const getUserByUsername = (phone_number:string) => UserModel.findOne({username});
export const getUserById = (id: string) => UserModel.findById(id);
export const createUser = (values: Record<string, any>) => new UserModel(values).save().then((user => user.toObject()));
export const comparePassword = (password:string, dbPassword:string)=>{
return bcrypt.compareSync(password, dbPassword);
}
Step 4 Create Controller for API
1. Resigter User
create new folder in root directory, which name is controllers. Under controller create new file authentications.ts.
export const register = async (req: express.Request, res: express.Response) => {
try {
const { email, username, password, name } = req.body;
if (!email || !username || !password || !name) {
return res.status(StatusCodes.BAD_REQUEST).json({ error: 'All fields (email, password, name) are required' });
}
const existingUserByEmail = await getUserByEmail(email);
if (existingUser) {
return res.status(StatusCodes.BAD_REQUEST).json({ message: 'User with this email already exists' });
}
const existingUserUsername = await getUserByPhone(username);
if(existingUserPhone){
return res.status(StatusCodes.BAD_REQUEST).json({message:'User with this Username already exists'});
}
const hashedPassword = await bcrypt.hash(password, 10);
const user = await createUser({
email,
name,
username,
password: hashedPassword
});
return res.status(StatusCodes.CREATED).json({
message: 'User registered successfully',
user: {
email: user.email,
name: user.name,
username: user.username,
createdAt: user.createdAt,
}
});
} catch (error) {
console.error('Registration error:', error);
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ message: 'Internal server error' });
}
};
-
Input fields and Validate inputs:
Extract all body request and checks if any of the required fields are missing. if missing then return 400 Bad Request with error message.
const { email, username, password, name } = req.body;
if (!email || !username || !password || !name) {
return res.status(StatusCodes.BAD_REQUEST).json({ error: 'All fields (email, password, name) are required' });
}
2. check for existring user:
Check is a user provided email and username already exists. is exists then reutrn 400 Bad Request with error message.
const existingUserByEmail = await getUserByEmail(email);
if (existingUser) {
return res.status(StatusCodes.BAD_REQUEST).json({ message: 'User with this email already exists' });
}
const existingUserUsername = await getUserByPhone(username);
if(existingUserPhone){
return res.status(StatusCodes.BAD_REQUEST).json({message:'User with this Username already exists'});
}
3. Hash Password and Create User
If no duplicate users are found, the function hashes then password using bcrypt with salt round of 10, then create a new user with createUser by storing details like email, name username and password.
const hashedPassword = await bcrypt.hash(password, 10);
const user = await createUser({
email,
name,
username,
password: hashedPassword
});
4. Return Success Response
Once the user is created then return response with 201 Created status.
return res.status(StatusCodes.CREATED).json({
message: 'User registered successfully',
user: {
email: user.email,
name: user.name,
username: user.username,
createdAt: user.createdAt,
}
});
2. Login User
export const login = async (req: express.Request, res: express.Response)=>{
try{
const {email, password} = req.body;
if(!email || !password){
return res.status(401);
}
const user = await getUserByEmail(email);
if(!user){
return res.status(StatusCodes.BAD_REQUEST).json({message:"user not found"});
}
if(user && user.password){
const checkPassword = comparePassword(password, user.password);
if(!checkPassword){
return res.status(StatusCodes.BAD_REQUEST).json({message:"Invalid password"});
}
const token = generateToken({id:user._id.toString(),
username:user.username,
role:(user.role as IRole).name
});
let data = {
token:token,
user:{
id:user._id,
name:user.name,
email:user.email,
createdAt:user.createdAt,
image:user.image?user.image:''
}
}
return res.status(StatusCodes.OK).json(data);
}
}catch(error:any){
console.log(error);
return res.status(StatusCodes.BAD_REQUEST).json({message:error.message});
}
}
// generate token
const generateToken = (user:any):string=>{
return jwt.sign(user, SECRET_KEY, {expiresIn:'1h'});
}
- Validate Login credentails:
Extracts email and password from the request body. If either fields is missing it. return a 401 Unauthorized response.
const { email, password } = req.body;
if (!email || !password) {
return res.status(401);
}
2. Fetch User details:
Find the user by email using getUserByEmail. If no user found, its returns a 400 Bad Request response with a message indicating that the user was not found.
const user = await getUserByEmail(email);
if (!user) {
return res.status(StatusCodes.BAD_REQUEST).json({ message: "user not found" });
}
if (user && user.password) {
const checkPassword = comparePassword(password, user.password);
if (!checkPassword) {
return res.status(StatusCodes.BAD_REQUEST).json({ message: "Invalid password" });
}
const token = generateToken({
id: user._id.toString(),
username: user.username,
role: (user.role as IRole).name
});
const generateToken = (user: any): string => {
return jwt.sign(user, SECRET_KEY, { expiresIn: '1h' });
}
import express from 'express';
import { login, register } from '../controllers/authentications';
import { isAuthenticated} from '../middlewares';
export default (router: express.Router) => {
router.post('/auth/register', register);
router.post('/auth/login', login);
router.get('/profile', isAuthenticated, userProfile);
}
import authentication from "./authentication";
const router = express.Router();
export default (): express.Router => {
authentication(router);
}
3. Create Meddlewares for validate User.
when user hit api, which api is authenticate API then check JWT token is valid or not.
export const isAuthenticated = async (req:express.Request, res:express.Response, next:express.NextFunction)=>{
try{
const token = req.headers.authorization?.split(" ")[1];
if(!token){
return res.status(StatusCodes.UNAUTHORIZED).json({error:'No token provided'});
}
req.user = verifyToken(token);
return next();
}catch(error){
return res.status(StatusCodes.UNAUTHORIZED).json({error:'Invalid token'});
}
}
// verify token
const verifyToken = (token:string):any =>{
return jwt.verify(token, SECRET_KEY) as JwtPayload;
}
Create new Api, which api is authenticated
router.get('/profile', isAuthenticated, userProfile);
Login to leave a comment.