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');

?>


1 comment:

  1. Hello, Thanks for your tutorial. I want through the script and had a complete installation on my local machine. I had a error from the SMTP though my username and password are all correct.

    This is the error i'm getting. Please any help. Thanks in advance

    Fatal error: Uncaught PHPMailer\PHPMailer\Exception: SMTP Error: Could not authenticate. in D:\xampp\htdocs\php_registeration_jwt\vendor\phpmailer\phpmailer\src\PHPMailer.php:2265 Stack trace: #0

    ReplyDelete