Showing posts with label token. Show all posts
Showing posts with label token. Show all posts

Tuesday, 13 February 2024

Simplifying User Authentication with JWT Tokens in Node.js


In modern web development, user authentication is a fundamental aspect of building secure applications. Implementing a login and registration system using JSON Web Tokens (JWT) in Node.js offers a robust solution that enhances security and simplifies user management. In this article, we'll explore how to implement user authentication using JWT tokens in a Node.js application.


Simplifying User Authentication with JWT Tokens in Node.js

What are JWT Tokens?


JWT tokens are an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. These tokens can be signed using a secret or a public/private key pair, providing a means of verifying the integrity of the information contained within.

  1. Step 1: Setting Up Your Node.js Environment
  2. Step 2: Creating the Express Server
  3. Step 3: Database Connection
  4. Step 4: Setting Up Routes
  5. Step 5: Implementing User Registration
  6. Step 6: Implementing User Login
  7. Step 7: Protecting Routes
  8. Step 8: Run Application
  9. Step 9: Conclusion

Step 1: Setting Up Your Node.js Environment


Ensure you have Node.js installed on your machine. If not, download and install it from the official Node.js website. Once installed, open your terminal and create a new directory for your project.

	
		mkdir node-jwt-auth
		cd node-jwt-auth
	

Initialize a new Node.js project and install the necessary dependencies.

	
		npm install express jsonwebtoken bcrypt body-parser mongoose
	

Step 2: Creating the Express Server


Create a file named app.js and set up a basic Express server.

app.js
	
		const express = require('express');
		const mysql = require('mysql2');
		const bcrypt = require('bcrypt');
		const jwt = require('jsonwebtoken');
		const app = express();
		const port = 3000;
		app.use(express.json());
		//Serve static files (including index.html) from the root directory
		app.use(express.static(__dirname));
	

Step 3: Database Connection


Under this app.js file we have to make MySQL Database connection. So user registration data will be stored under MySQL database.

app.js
	
		const database = mysql.createConnection({
			host : 'localhost',
			user : 'root',
			password : '123456789',
			database : 'testing'
		});

		database.connect((error)=> {
			if(error){
				console.error('Error connecting to MySQL : ', error);
			} else{
				console.log('Connected to MySQL database');
			}
		});
	

It will make database connection and also check that there is any error has been occured during database connection.

Below you can find MySQL table structure for user table. So you have to copy this .sql code and run in local MySQL database. So it will create user under which registration data will be stored.

	
		CREATE TABLE `user` (
		  `user_id` int NOT NULL AUTO_INCREMENT,
		  `user_email` varchar(70) DEFAULT NULL,
		  `user_password` varchar(70) DEFAULT NULL,
		  `user_name` varchar(45) DEFAULT NULL,
		  `email_verification_status` enum('Not Verified','Verified') DEFAULT NULL,
		  PRIMARY KEY (`user_id`)
		) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
	

Step 4: Setting Up Routes


Create routes under app.js file for handling user authentication and registration.

app.js
	
		app.get('/', (request, response)=>{
		
		});
		
		app.post('/register', async (request, response)=>{
		
		});
	

Define routes for user registration, login, and protected resources in the respective files.

Step 5: Implementing User Registration


First we have goes into '/' get route, and under this we have to write following code which will load index.html file on browser.

app.js
	
		app.get('/', (request, response)=>{
			response.sendFile(__dirname + '/index.html');
		});
	

After this, we have goes to index.html file and under this we have to create register form and then after we have to write JavaScript code for submit register form data using JavaScript fetch API. And here we have also use try catch block of handle error at front end side.

index.html
	
		<!doctype html>
		<html lang="en">
			<head>
				<!-- Required meta tags -->
				<meta charset="utf-8">
				<meta name="viewport" content="width=device-width, initial-scale=1">

				<!-- Bootstrap CSS -->
				<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

				<title>Node.js Login Register using JWT Token</title>
			</head>
			<body>				
				<div class="container">
					<h1 class="text-center mb-5 mt-5">Node.js Login Register using JWT Token</h1>
					<div class="row">
						<div class="col col-4"> </div>
						<div class="col col-4">
							<span id="msgArea"></span>
							<div class="card">
								<div class="card-header">Register</div>
								<div class="card-body">
									<form id="registerForm">
										<div class="mb-3">
											<label><b>Name</b></label>
											<input type="text" name="name" id="name" class="form-control" />
										</div>
										<div class="mb-3">
											<label><b>eMail</b></label>
											<input type="text" name="email" id="email" class="form-control" />
										</div>
										<div class="mb-3">
											<label><b>Password</b></label>
											<input type="password" name="password" id="password" class="form-control" />
										</div>
										<input type="submit" class="btn btn-primary" value="Register" />
									</form>
								</div>
							</div>
						</div>
					</div>
				</div>

				<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
			</body>
		</html>

		<script>

		document.getElementById("registerForm").addEventListener('submit', async function(event){
			event.preventDefault();
			const name = document.getElementById("name").value;
			const email = document.getElementById("email").value;
			const password = document.getElementById("password").value;
			let messageArea = document.getElementById("msgArea");
			try{
				const response = await fetch('/register', {
					method : 'POST',
					headers : {
						'Content-Type': 'application/json'
					},
					body : JSON.stringify({name, email, password})
				});
				if(response.ok){
					messageArea.innerHTML = '<div class="alert alert-success">User registered successfully!</div>';
				} else {
					const data = await response.json();
					messageArea.innerHTML = `<div class="alert alert-info">Error : ${data.error}</div>`;
				}

			} catch(error){
				messageArea.innerHTML = '<div class="alert alert-danger">Internal Server Error</div>';
			}
		});

		</script>
	

Now in app.js, implement the route for user registration. Hash the user's password using bcrypt before storing it in the database and here it has also check email is already exists or not also.

app.js
	
		app.post('/register', async (request, response)=>{
			try{
				const {name, email, password} = request.body;
				if(!name || !email || !password){
					return response.status(400).json({error : 'Please provide all required fields'});
				}
				// Check if the email already exists in the database
				database.query('SELECT * FROM user WHERE user_email = ?', [email], async (error, results) =>{
					if(error){
						return response.status(500).json({error : 'Internal Server Error'});
					}
					if(results.length > 0){
						return response.status(400).json({error : 'Email already exists'});
					}
					const hashedPassword = await bcrypt.hash(password, 10);
					//Insert registeration data
					database.query('INSERT INTO user (user_email, user_password, user_name) VALUES (?, ?, ?)', [email, hashedPassword, name], (error) => {
						if(error){
							console.log(error);
							return response.status(500).json({error : 'Internal Server Error'});
						}
						return response.status(201).json({message : 'User registered successfully'});
					});
				});
			} catch(error){
				response.status(500).json({error : 'Internal Server Error'});
			}
		});
		app.listen(port, () => {
			console.log(`Server is running on http://localhost:${port}`);   
		});
	

Step 6: Implementing User Login


Now for create Login in this Node JS Application, first in app.js file we have go create route for load login form in the browser.

app.js
	
		app.get('/login', (request, response) => {
			response.sendFile(__dirname + '/login.html');
		});
	

So it will send login.html file in browser and display login login form on web page.

Next we have to create login.html file and under this file, we will write HTML code for display Login form and JavaScript code for submit login form data to server.

login.html
	
		<!doctype html>
		<html lang="en">
			<head>
				<!-- Required meta tags -->
				<meta charset="utf-8">
				<meta name="viewport" content="width=device-width, initial-scale=1">

				<!-- Bootstrap CSS -->
				<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

				<title>Node.js Login Register using JWT Token</title>
			</head>
			<body>
				
				<div class="container">
					<h1 class="text-center mb-5 mt-5">Node.js Login Register using JWT Token</h1>
					<div class="row">
						<div class="col col-4"> </div>
						<div class="col col-4">
							<span id="msgArea"></span>
							<div class="card">
								<div class="card-header">Login</div>
								<div class="card-body">
									<form id="loginForm">
										<div class="mb-3">
											<label><b>eMail</b></label>
											<input type="text" name="email" id="email" class="form-control" />
										</div>
										<div class="mb-3">
											<label><b>Password</b></label>
											<input type="password" name="password" id="password" class="form-control" />
										</div>
										<input type="submit" class="btn btn-primary" value="Login" />
									</form>
								</div>
							</div>
						</div>
					</div>
				</div>

				<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
			</body>
		</html>

		<script>

		document.getElementById('loginForm').addEventListener('submit', async function(event){
			event.preventDefault();
			const email = document.getElementById('email').value;
			const password = document.getElementById('password').value;
			try {
				const response = await fetch('/login', {
					method : 'POST',
					headers : {
						'Content-Type': 'application/json',
					},
					body : JSON.stringify({ email, password })
				});
				const data = await response.json();
				if(response.ok){
					localStorage.setItem('token', data.token);
					window.location.href = '/welcome';
				} else {
					document.getElementById('msgArea').innerHTML = `<div class="alert alert-info">Error : ${data.error}</div>`;
				}
			} catch(error){
				document.getElementById('msgArea').innerHTML = '<div class="alert alert-danger">Internal Server Error</div>';
			}
		});

		</script>
	

Once login form data has been submitted then it will send login data to /login route of app.js file. And under this file it will validate user login data and here it also also compare simple login form password with hashed formatted password which is stored in database by using bcrypt library.

app.js
	
		app.post('/login', async (request, response) => {
			try {
				const {email, password} = request.body;
				if(!email || !password){
					return response.status(400).json({ error : 'Please provide all required fields'});
				}
				database.query('SELECT * FROM user WHERE user_email = ?', [email], async (error, results) => {
					if(results.length > 0){
						const user = results[0];
						if(await bcrypt.compare(password, user.user_password)){
							const token = jwt.sign({ userId : user.user_id }, secretKey, { expiresIn : '1h' });
							response.status(200).json({ token });
						} else {
							response.status(401).json({ error : 'Wrong Password' });
						}
					} else {
						response.status(401).json({ error : 'Wrong Email' });
					}
				});
			} catch(error){
				response.status(500).json({ error : 'Internal Server Error' });
			}
		});
	

Step 7: Protecting Routes


Once we have make login page, when user has been login into system then user data has been stored in JWT token. Now we want to verify that user has been login into system or not. So for this we have to make one middleware to check user is login or not. In middleware it will decode JWT token data and then after it has authenticate that user is login or not.

So for this first we have to create one button, so when we have click on that button then it will send request to Node server route for fetch data from JWT token. So when we have send request to server, then in header it will send encoded JWT token data.

welcome.html
	
		<!doctype html>
		<html lang="en">
			<head>
				<!-- Required meta tags -->
				<meta charset="utf-8">
				<meta name="viewport" content="width=device-width, initial-scale=1">

				<!-- Bootstrap CSS -->
				<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

				<title>Node.js Login Register using JWT Token</title>
			</head>
			<body>
				
				<div class="container">
					<h1 class="text-center mb-5 mt-5">Node.js Login Register using JWT Token</h1>
					<div class="row">
						<div class="col col-4"> </div>
						<div class="col col-4">
							<span id="msgArea"></span>
							<div class="card">
								<div class="card-header">Welcome Page</div>
								<div class="card-body">
									<h1 class="text-center">Welcome User</h1>
									<p class="text-center">
										<button type="button" class="btn btn-warning" onclick="getJWTData()">Get User ID</button>
										<button type="button" onclick="logout()" class="btn btn-primary">Logout</button>
									</p>
								</div>
							</div>
						</div>
					</div>
				</div>

				<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
			</body>
		</html>

		<script>

		const token = localStorage.getItem('token');
		if(!token){
			window.location.href = '/login';
		}

		function logout(){
			localStorage.removeItem('token');
			window.location.href = '/login';
		}

		function getJWTData(){
			fetch('/getJWTData', {
				headers : {
					'Authorization' : token
				}
			})
			.then(response => {
				return response.json();
			})
			.then(data => {
				alert(`Login User ID is - ${data.userId}`);
			})
			.catch(error => {
				alert(error);
			});
		}

		</script>
	

Now at Node backend side code, we have to create getJWTData route and under this route we have to add verifyToken middleware. So this middleware code will be first executed and it will first receive JWT token data from HTTP header. And then after by using JWT library it will again decode that data. If data has been successfully decoded that it will execute other part of code. But Suppose there JWT token not found in HTTP headers then it will directly send error to client without executing next code. But suppose data has been decoded from JWT token then it will send back that data to client which will be pop up on web page. So this way it will fetch data from JWT token under Node JS application.

app.js
	
		// Middleware to check JWT token
		function verifyToken(request, response, next){
			const token = request.headers.authorization;
			if(!token){
				return response.status(401).json({ error : 'Access denied. No token provided.'});
			}
			try {
				const decoded = jwt.verify(token, secretKey);
				request.user = decoded;
				next();
			} catch(error){
				response.status(401).json({ error : 'Invalid token' });
			}
		}

		app.get('/getJWTData', verifyToken, (request, response) => {
			response.status(200).json({ userId : request.user.userId });
		});
	

Step 8: Run Application


Once our code is ready, now for check output in browser, we have goes to terminal and run node app.js command which will start node server.

And in browser we can open this Node application by open http://localhost:3000 this url.

Step 9: Conclusion


You've successfully implemented a login and registration system using JWT tokens in your Node.js application. This provides a secure way to manage user sessions and protect sensitive resources. With the flexibility of Node.js and the simplicity of JWT tokens, you can now build robust authentication systems for your web applications.

Complete Source Code


app.js
	
		const express = require('express');
		const mysql = require('mysql2');
		const bcrypt = require('bcrypt');
		const jwt = require('jsonwebtoken');
		const app = express();
		const port = 3000;
		app.use(express.json());
		//Serve static files (including index.html) from the root directory
		app.use(express.static(__dirname));
		const database = mysql.createConnection({
			host : 'localhost',
			user : 'root',
			password : '123456789',
			database : 'testing'
		});

		database.connect((error)=> {
			if(error){
				console.error('Error connecting to MySQL : ', error);
			} else{
				console.log('Connected to MySQL database');
			}
		});

		const secretKey = 'eyJhbGciOiJIUzI1NiJ9.eyJSb2xlIjoiQWRtaW4iLCJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkphdmFJblVzZSIsImV4cCI6MTcwNjg3ODE1MywiaWF0IjoxNzA2ODc4MTUzfQ.i4j208HUwM7JjLJL98o9EkE68Ia87i694iq7r67zRHM';

		app.get('/', (request, response)=>{
			response.sendFile(__dirname + '/index.html');
		});

		app.post('/register', async (request, response)=>{
			try{
				const {name, email, password} = request.body;
				if(!name || !email || !password){
					return response.status(400).json({error : 'Please provide all required fields'});
				}
				// Check if the email already exists in the database
				database.query('SELECT * FROM user WHERE user_email = ?', [email], async (error, results) =>{
					if(error){
						return response.status(500).json({error : 'Internal Server Error'});
					}
					if(results.length > 0){
						return response.status(400).json({error : 'Email already exists'});
					}
					const hashedPassword = await bcrypt.hash(password, 10);
					//Insert registeration data
					database.query('INSERT INTO user (user_email, user_password, user_name) VALUES (?, ?, ?)', [email, hashedPassword, name], (error) => {
						if(error){
							console.log(error);
							return response.status(500).json({error : 'Internal Server Error'});
						}
						return response.status(201).json({message : 'User registered successfully'});
					});
				});
			} catch(error){
				response.status(500).json({error : 'Internal Server Error'});
			}
		});

		app.get('/login', (request, response) => {
			response.sendFile(__dirname + '/login.html');
		});

		app.post('/login', async (request, response) => {
			try {
				const {email, password} = request.body;
				if(!email || !password){
					return response.status(400).json({ error : 'Please provide all required fields'});
				}
				database.query('SELECT * FROM user WHERE user_email = ?', [email], async (error, results) => {
					if(results.length > 0){
						const user = results[0];
						if(await bcrypt.compare(password, user.user_password)){
							const token = jwt.sign({ userId : user.user_id }, secretKey, { expiresIn : '1h' });
							response.status(200).json({ token });
						} else {
							response.status(401).json({ error : 'Wrong Password' });
						}
					} else {
						response.status(401).json({ error : 'Wrong Email' });
					}
				});
			} catch(error){
				response.status(500).json({ error : 'Internal Server Error' });
			}
		});

		app.get('/welcome', (request, response) => {
			response.sendFile(__dirname + '/welcome.html');
		});

		// Middleware to check JWT token
		function verifyToken(request, response, next){
			const token = request.headers.authorization;
			if(!token){
				return response.status(401).json({ error : 'Access denied. No token provided.'});
			}
			try {
				const decoded = jwt.verify(token, secretKey);
				request.user = decoded;
				next();
			} catch(error){
				response.status(401).json({ error : 'Invalid token' });
			}
		}

		app.get('/getJWTData', verifyToken, (request, response) => {
			response.status(200).json({ userId : request.user.userId });
		});


		app.listen(port, () => {
			console.log(`Server is running on http://localhost:${port}`);   
		});
	

index.html
	
		<!doctype html>
		<html lang="en">
			<head>
				<!-- Required meta tags -->
				<meta charset="utf-8">
				<meta name="viewport" content="width=device-width, initial-scale=1">

				<!-- Bootstrap CSS -->
				<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

				<title>Node.js Login Register using JWT Token</title>
			</head>
			<body>
				
				<div class="container">
					<h1 class="text-center mb-5 mt-5">Node.js Login Register using JWT Token</h1>
					<div class="row">
						<div class="col col-4"> </div>
						<div class="col col-4">
							<span id="msgArea"></span>
							<div class="card">
								<div class="card-header">Register</div>
								<div class="card-body">
									<form id="registerForm">
										<div class="mb-3">
											<label><b>Name</b></label>
											<input type="text" name="name" id="name" class="form-control" />
										</div>
										<div class="mb-3">
											<label><b>eMail</b></label>
											<input type="text" name="email" id="email" class="form-control" />
										</div>
										<div class="mb-3">
											<label><b>Password</b></label>
											<input type="password" name="password" id="password" class="form-control" />
										</div>
										<input type="submit" class="btn btn-primary" value="Register" />
									</form>
								</div>
							</div>
						</div>
					</div>
				</div>

				<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
			</body>
		</html>

		<script>

		document.getElementById("registerForm").addEventListener('submit', async function(event){
			event.preventDefault();
			const name = document.getElementById("name").value;
			const email = document.getElementById("email").value;
			const password = document.getElementById("password").value;
			let messageArea = document.getElementById("msgArea");
			try{
				const response = await fetch('/register', {
					method : 'POST',
					headers : {
						'Content-Type': 'application/json'
					},
					body : JSON.stringify({name, email, password})
				});
				if(response.ok){
					messageArea.innerHTML = '<div class="alert alert-success">User registered successfully!</div>';
				} else {
					const data = await response.json();
					messageArea.innerHTML = `<div class="alert alert-info">Error : ${data.error}</div>`;
				}

			} catch(error){
				messageArea.innerHTML = '<div class="alert alert-danger">Internal Server Error</div>';
			}
		});

		</script>
	

login.html
	
		<!doctype html>
		<html lang="en">
			<head>
				<!-- Required meta tags -->
				<meta charset="utf-8">
				<meta name="viewport" content="width=device-width, initial-scale=1">

				<!-- Bootstrap CSS -->
				<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

				<title>Node.js Login Register using JWT Token</title>
			</head>
			<body>
				
				<div class="container">
					<h1 class="text-center mb-5 mt-5">Node.js Login Register using JWT Token</h1>
					<div class="row">
						<div class="col col-4"> </div>
						<div class="col col-4">
							<span id="msgArea"></span>
							<div class="card">
								<div class="card-header">Login</div>
								<div class="card-body">
									<form id="loginForm">
										<div class="mb-3">
											<label><b>eMail</b></label>
											<input type="text" name="email" id="email" class="form-control" />
										</div>
										<div class="mb-3">
											<label><b>Password</b></label>
											<input type="password" name="password" id="password" class="form-control" />
										</div>
										<input type="submit" class="btn btn-primary" value="Login" />
									</form>
								</div>
							</div>
						</div>
					</div>
				</div>

				<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
			</body>
		</html>

		<script>

		document.getElementById('loginForm').addEventListener('submit', async function(event){
			event.preventDefault();
			const email = document.getElementById('email').value;
			const password = document.getElementById('password').value;
			try {
				const response = await fetch('/login', {
					method : 'POST',
					headers : {
						'Content-Type': 'application/json',
					},
					body : JSON.stringify({ email, password })
				});
				const data = await response.json();
				if(response.ok){
					localStorage.setItem('token', data.token);
					window.location.href = '/welcome';
				} else {
					document.getElementById('msgArea').innerHTML = `<div class="alert alert-info">Error : ${data.error}</div>`;
				}
			} catch(error){
				document.getElementById('msgArea').innerHTML = '<div class="alert alert-danger">Internal Server Error</div>';
			}
		});

		</script>
	

welcome.html
	
		<!doctype html>
		<html lang="en">
			<head>
				<!-- Required meta tags -->
				<meta charset="utf-8">
				<meta name="viewport" content="width=device-width, initial-scale=1">

				<!-- Bootstrap CSS -->
				<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

				<title>Node.js Login Register using JWT Token</title>
			</head>
			<body>
				
				<div class="container">
					<h1 class="text-center mb-5 mt-5">Node.js Login Register using JWT Token</h1>
					<div class="row">
						<div class="col col-4"> </div>
						<div class="col col-4">
							<span id="msgArea"></span>
							<div class="card">
								<div class="card-header">Welcome Page</div>
								<div class="card-body">
									<h1 class="text-center">Welcome User</h1>
									<p class="text-center">
										<button type="button" class="btn btn-warning" onclick="getJWTData()">Get User ID</button>
										<button type="button" onclick="logout()" class="btn btn-primary">Logout</button>
									</p>
								</div>
							</div>
						</div>
					</div>
				</div>

				<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
			</body>
		</html>

		<script>

		const token = localStorage.getItem('token');
		if(!token){
			window.location.href = '/login';
		}

		function logout(){
			localStorage.removeItem('token');
			window.location.href = '/login';
		}

		function getJWTData(){
			fetch('/getJWTData', {
				headers : {
					'Authorization' : token
				}
			})
			.then(response => {
				return response.json();
			})
			.then(data => {
				alert(`Login User ID is - ${data.userId}`);
			})
			.catch(error => {
				alert(error);
			});
		}

		</script>
	



Tuesday, 9 January 2024

Mastering User Registration and Email Verification in PHP with JWT Tokens: A Comprehensive Guide


In the ever-evolving landscape of web development, ensuring a secure and streamlined user registration process is paramount. One powerful way to enhance the security of your PHP-based applications is by implementing user registration and email verification using JSON Web Tokens (JWT). In this guide, we'll walk you through the process step by step, empowering you to bolster the authentication mechanisms of your PHP projects.


Mastering User Registration and Email Verification in PHP with JWT Tokens: A Comprehensive Guide


Understanding the Basics


What is JWT?


JSON Web Tokens (JWT) provide a secure and compact way to transmit information between parties. In the context of user authentication, JWTs can be used to securely store user data and ensure that information is not tampered with during transmission.

Why PHP?


PHP remains a popular server-side scripting language, particularly for web development. Its versatility, ease of use, and extensive community support make it an excellent choice for implementing robust authentication systems.

Step-by-Step Guide


1. Setting Up Your PHP Environment


Ensure that your PHP environment is configured correctly. This includes setting up a database to store user information securely.


CREATE TABLE `user` (
  `user_id` int NOT NULL AUTO_INCREMENT,
  `user_email` varchar(70) DEFAULT NULL,
  `user_password` varchar(45) DEFAULT NULL,
  `user_name` varchar(45) DEFAULT NULL,
  `email_verification_status` enum('Not Verified','Verified') DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO `user` VALUES (1,'johnsmith@gmail.com','password','John Smith','Verified'),(16,'peterparker@mailinator.com','password','Peter Parker','Verified'),(17,'donna@mailinator.com','password','Donna Hubber','Verified'),(18,'mike@mailinator.com','password','Mike','Verified');


2. Integrating JWT Library


Choose a reliable JWT library for PHP, such as Firebase JWT. Integrate it into your project to start creating and validating JWTs.


composer require firebase/php-jwt


3. User Registration


Implement a user registration system that securely stores user data in your database. Hash passwords using strong encryption algorithms to enhance security.

4. Generating JWTs


Upon successful registration, generate a JWT containing relevant user information. This token will serve as a secure means of verifying the user's identity in subsequent requests.

5. Email Verification


Send a verification email containing a link with a JWT to the user's registered email address. This link will confirm the user's identity and activate their account.

6. Token Validation


Implement a mechanism to validate JWTs in subsequent user requests. This ensures that only authenticated users can access protected resources.

Best Practices and Security Measures


1. Use HTTPS


Ensure your application is served over HTTPS to encrypt data transmitted between the user and the server, preventing man-in-the-middle attacks.

2. Token Expiry


Set a reasonable expiration time for your JWTs to mitigate the risk of unauthorized access.

3. Secure Database Storage


Employ secure practices for storing user data in the database, such as hashing and salting passwords.

4. Rate Limiting


Implement rate limiting to prevent brute-force attacks on the authentication system.

Conclusion


By following this comprehensive guide, you'll be well-equipped to implement a robust user registration and email verification system using PHP and JWT. Enhance the security of your applications, protect user data, and provide a seamless experience for your users. Stay ahead in the world of web development by mastering the art of authentication with PHP and JWT tokens.





Source Code


register.php

<?php 

//register.php

require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

$error = '';

$message = '';

if(isset($_POST['register']))
{
	$connect = new PDO("mysql:host=localhost; dbname=testing", "root", "password");

	if(empty($_POST['name']))
	{
		$error = 'Please Enter Name Details';
	}
	else if(empty($_POST['email']))
	{
		$error = 'Please Enter Email Details';
	}
	else if(empty($_POST['password']))
	{
		$error = 'Please Enter Password Details';
	}
	else
	{
		$query = "SELECT user_id FROM user WHERE user_email = ?";
		$statement = $connect->prepare($query);
		$statement->execute([$_POST["email"]]);
		if($statement->rowCount() > 0)
		{
			$error = 'Email Alaready Exists';
		}
		else
		{
			$data = array(
				':user_email'		=>	trim($_POST['email']),
				':user_password'	=>	trim($_POST['password']),
				':user_name'		=>	trim($_POST['name']),
				':email_verification_status'	=>	'Not Verified'
			);

			$insertQuery = "INSERT INTO user (user_email, user_password, user_name, email_verification_status) VALUES (:user_email, :user_password, :user_name, :email_verification_status)";
			$statement = $connect->prepare($insertQuery);
			if($statement->execute($data))
			{
				$key = '1a3LM3W966D6QTJ5BJb9opunkUcw_d09NCOIJb9QZTsrneqOICoMoeYUDcd_NfaQyR787PAH98Vhue5g938jdkiyIZyJICytKlbjNBtebaHljIR6-zf3A2h3uy6pCtUFl1UhXWnV6madujY4_3SyUViRwBUOP-UudUL4wnJnKYUGDKsiZePPzBGrF4_gxJMRwF9lIWyUCHSh-PRGfvT7s1mu4-5ByYlFvGDQraP4ZiG5bC1TAKO_CnPyd1hrpdzBzNW4SfjqGKmz7IvLAHmRD-2AMQHpTU-hN2vwoA-iQxwQhfnqjM0nnwtZ0urE6HjKl6GWQW-KLnhtfw5n_84IRQ';

				$payload = array(
					'email'		=>	trim($_POST['email'])
				);

				$token = JWT::encode($payload, $key, 'HS256');

				$verificationLink = 'http://localhost/tutorial/php-jwt-login/verify.php?token='.$token;

				$mail = new PHPMailer(true);
				$mail->isSMTP();
				$mail->Host = 'smtp.gmail.com';
				$mail->SMTPAuth = true;
				$mail->Username = 'your gmail address';
				$mail->Password = 'xxx'; //Here you have to define your gmail password
				$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
				$mail->Port = 587;
				$mail->setFrom('sender@email.com', 'sender@email.com');
				$mail->addAddress(trim($_POST['email']), trim($_POST['name']));
				$mail->isHTML(true);
				$mail->Subject = 'Verify Your Email Address';
				$mail->Body = '
				<p>Hi,</p>
			    <p>Thank you for registering with us! To complete your registration and activate your account, please click on the following link:</p>
			    <p><a href="'.$verificationLink.'">'.$verificationLink.'</a></p>
			    <p>Thank you,<br />Webslesson.info</p>
				';
				$mail->send();
				$message = 'Verification eMail has been send! Registration Complete!';
			}
		}
	}
}

?>

<!doctype html>
<html lang="en">
  	<head>
    	<!-- Required meta tags -->
    	<meta charset="utf-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1">

    	<!-- Bootstrap CSS -->
    	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    	<title>PHP Registration & Email Validation using JWT Token</title>
  	</head>
  	<body>
    	<div class="container">
    		<h1 class="text-center mt-5 mb-5">PHP Registration & Email Validation using JWT Token</h1>
    		<div class="row">
    			<div class="col-md-4">&nbsp;</div>
    			<div class="col-md-4">
    				<?php

    				if($error !== '')
    				{
    					echo '<div class="alert alert-danger">'.$error.'</div>';
    				}

    				if($message !== '')
    				{
    					echo '<div class="alert alert-success">'.$message.'</div>';
    				}

    				?>
		    		<div class="card">
		    			<div class="card-header">Register</div>
		    			<div class="card-body">
		    				<form method="post">
		    					<div class="mb-3">
			    					<label>Name</label>
			    					<input type="text" name="name" class="form-control" />
			    				</div>
			    				<div class="mb-3">
			    					<label>Email</label>
			    					<input type="email" name="email" class="form-control" />
			    				</div>
			    				<div class="mb-3">
			    					<label>Password</label>
			    					<input type="password" name="password" class="form-control" />
			    				</div>
			    				<div class="text-center">
			    					<input type="submit" name="register" value="Register" class="btn btn-primary" />
			    				</div>
		    				</form>
		    			</div>
		    		</div>
		    	</div>
	    	</div>
    	</div>
  	</body>
</html>


verify.php

<?php

//verify.php

require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$key = '1a3LM3W966D6QTJ5BJb9opunkUcw_d09NCOIJb9QZTsrneqOICoMoeYUDcd_NfaQyR787PAH98Vhue5g938jdkiyIZyJICytKlbjNBtebaHljIR6-zf3A2h3uy6pCtUFl1UhXWnV6madujY4_3SyUViRwBUOP-UudUL4wnJnKYUGDKsiZePPzBGrF4_gxJMRwF9lIWyUCHSh-PRGfvT7s1mu4-5ByYlFvGDQraP4ZiG5bC1TAKO_CnPyd1hrpdzBzNW4SfjqGKmz7IvLAHmRD-2AMQHpTU-hN2vwoA-iQxwQhfnqjM0nnwtZ0urE6HjKl6GWQW-KLnhtfw5n_84IRQ';

$token = '';
$payload = array();

if(isset($_GET['token']))
{
	$connect = new PDO("mysql:host=localhost; dbname=testing", "root", "password");
	$decoded = JWT::decode($_GET['token'], new Key($key, 'HS256'));
	$checkQuery = 'SELECT email_verification_status FROM user WHERE user_email = "'.$decoded->email.'"';
	$result = $connect->query($checkQuery);
	foreach($result as $row)
	{
		if($row['email_verification_status'] === 'Verified')
		{
			$payload = array(
				'msg'	=>	'Your Email Already Verified, You can login'
			);
		}
		else
		{
			$query = 'UPDATE user SET email_verification_status = "Verified" WHERE user_email = "'.$decoded->email.'"';
			$statement = $connect->prepare($query);
			$statement->execute();
			$payload = array(
				'msg'	=>	'Email Successfully verify, now you can login'
			);
		}
		$token = JWT::encode($payload, $key, 'HS256');
		header('location:index.php?token='.$token);
	}
}

?>


index.php

<?php

//index.php

require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$key = '1a3LM3W966D6QTJ5BJb9opunkUcw_d09NCOIJb9QZTsrneqOICoMoeYUDcd_NfaQyR787PAH98Vhue5g938jdkiyIZyJICytKlbjNBtebaHljIR6-zf3A2h3uy6pCtUFl1UhXWnV6madujY4_3SyUViRwBUOP-UudUL4wnJnKYUGDKsiZePPzBGrF4_gxJMRwF9lIWyUCHSh-PRGfvT7s1mu4-5ByYlFvGDQraP4ZiG5bC1TAKO_CnPyd1hrpdzBzNW4SfjqGKmz7IvLAHmRD-2AMQHpTU-hN2vwoA-iQxwQhfnqjM0nnwtZ0urE6HjKl6GWQW-KLnhtfw5n_84IRQ';

$message = '';
$error = '';

if(isset($_GET['token']))
{
	$decoded = JWT::decode($_GET['token'], new Key($key, 'HS256'));
	$message = $decoded->msg;
}

if(isset($_POST["login"]))
{
	$connect = new PDO("mysql:host=localhost;dbname=testing", "root", "password");

	if(empty($_POST["email"])){
		$error = 'Please Enter Email Details';
	} else if(empty($_POST["password"])){
		$error = 'Please Enter Password Details';
	} else {
		$query = "SELECT * FROM user WHERE user_email = ?";
		$statement = $connect->prepare($query);
		$statement->execute([$_POST["email"]]);
		$data = $statement->fetch(PDO::FETCH_ASSOC);
		if($data){
			if($data['user_password'] ===  $_POST['password']){
				
				$token = JWT::encode(
					array(
						'iat'		=>	time(),
						'nbf'		=>	time(),
						'exp'		=>	time() + 3600,
						'data'	=> array(
							'user_id'	=>	$data['user_id'],
							'user_name'	=>	$data['user_name']
						)
					),
					$key,
					'HS256'
				);
				setcookie("token", $token, time() + 3600, "/", "", true, true);
				header('location:welcome.php');

			} else {
				$error = 'Wrong Password';
			}
		} else {
			$error = 'Wrong Email Address';
		}
	}
}

?>


<!doctype html>
<html lang="en">
  	<head>
    	<!-- Required meta tags -->
    	<meta charset="utf-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1">

    	<!-- Bootstrap CSS -->
    	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    	<title>How to Create Login using JWT Token in PHP</title>
  	</head>
  	<body>
    	<div class="container">
    		<h1 class="text-center mt-5 mb-5">How to Create Login using JWT Token in PHP</h1>
    		<div class="row">
    			<div class="col-md-4">&nbsp;</div>
    			<div class="col-md-4">
    				<?php

    				if($error !== '')
    				{
    					echo '<div class="alert alert-danger">'.$error.'</div>';
    				}

    				if($message !== '')
    				{
    					echo '<div class="alert alert-info">'.$message.'</div>';
    				}

    				?>
		    		<div class="card">
		    			<div class="card-header">Login</div>
		    			<div class="card-body">
		    				<form method="post">
		    					<div class="mb-3">
			    					<label>Email</label>
			    					<input type="email" name="email" class="form-control" />
			    				</div>
			    				<div class="mb-3">
			    					<label>Password</label>
			    					<input type="password" name="password" class="form-control" />
			    				</div>
			    				<div class="text-center">
			    					<input type="submit" name="login" class="btn btn-primary" value="Login" />
			    				</div>
		    				</form>
		    			</div>
		    		</div>
		    	</div>
	    	</div>
    	</div>
  	</body>
</html>


welcome.php

<?php

//welcome.php

require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$key = '1a3LM3W966D6QTJ5BJb9opunkUcw_d09NCOIJb9QZTsrneqOICoMoeYUDcd_NfaQyR787PAH98Vhue5g938jdkiyIZyJICytKlbjNBtebaHljIR6-zf3A2h3uy6pCtUFl1UhXWnV6madujY4_3SyUViRwBUOP-UudUL4wnJnKYUGDKsiZePPzBGrF4_gxJMRwF9lIWyUCHSh-PRGfvT7s1mu4-5ByYlFvGDQraP4ZiG5bC1TAKO_CnPyd1hrpdzBzNW4SfjqGKmz7IvLAHmRD-2AMQHpTU-hN2vwoA-iQxwQhfnqjM0nnwtZ0urE6HjKl6GWQW-KLnhtfw5n_84IRQ';

if(isset($_COOKIE['token'])){
	$decoded = JWT::decode($_COOKIE['token'], new Key($key, 'HS256'));
} else {
	header('location:index.php');
}

?>

<!doctype html>
<html lang="en">
  	<head>
    	<!-- Required meta tags -->
    	<meta charset="utf-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1">

    	<!-- Bootstrap CSS -->
    	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    	<title>How to Create Login in PHP using JWT Token</title>
  	</head>
  	<body>
    	<div class="container">
    		<h1 class="text-center mt-5 mb-5">How to Create Login in PHP using JWT Token</h1>
    		<div class="row">
    			<div class="col-md-4">&nbsp;</div>
    			<div class="col-md-4 text-center">
    				<h1>Welcome <b><?php echo $decoded->data->user_name; ?></b></h1>
    				<a href="logout.php">Logout</a>
    				
		    	</div>
	    	</div>
    	</div>
  	</body>
</html>


logout.php

<?php

//logout.php

setcookie("token", "", time() - 3600,  "/", "", true, true);

header('location:index.php');

?>