Authentication is a crucial aspect of web development to ensure secure access to resources and protect user data. In PHP, developers have multiple options for implementing authentication, with JWT (JSON Web Tokens) and OAuth being two popular choices. In this post, we'll explore the differences between JWT and OAuth and provide a full example of implementing authentication using JWT with a Bootstrap UI for the frontend.
Understanding JWT and OAuth
JWT (JSON Web Tokens): JWT is a compact and self-contained way of representing information between two parties as a JSON object. It is commonly used for user authentication, as it securely transmits data between the server and client in the form of a token.
OAuth (Open Authorization): OAuth is an authorization framework that enables third-party applications to access resources on behalf of a user. It allows users to grant limited access to their data to other applications without sharing their credentials.
Setting Up the Project
For this example, we'll use PHP for the backend and Bootstrap for the frontend.
Create Project Structure
Create a new directory for your project and set up the following folder structure:
- backend
- index.php
- composer.json
- composer.lock
- frontend
- index.html
- assets
- css
- bootstrap.min.css
- js
- bootstrap.bundle.min.js
- jquery.min.js
- Backend: Installing Dependencies
In the backend
directory, initialize a new Composer project and install the required dependencies:
composer init
composer require firebase/php-jwt
Implementing JWT Authentication
- Create
index.php
Open index.php
in the backend
directory and set up the basic PHP script with JWT authentication:
<?php
require __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
$secretKey = 'your-secret-key'; // Replace this with your own secret key
$tokenExpiration = 3600; // 1 hour
// Sample user data (replace with your database query to fetch user data)
$user = [
'id' => 1,
'username' => 'john_doe',
];
// Generate JWT token
function generateToken($user)
{
global $secretKey, $tokenExpiration;
$payload = [
'user_id' => $user['id'],
'username' => $user['username'],
'exp' => time() + $tokenExpiration,
];
return JWT::encode($payload, $secretKey);
}
// Verify JWT token
function verifyToken($token)
{
global $secretKey;
try {
$decoded = JWT::decode($token, $secretKey, ['HS256']);
return (array) $decoded;
} catch (Exception $e) {
return false;
}
}
// Handle login request
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['username']) && isset($_POST['password'])) {
// Validate user credentials (replace with your authentication logic)
if ($_POST['username'] === 'john_doe' && $_POST['password'] === 'password') {
$userToken = generateToken($user);
echo json_encode(['token' => $userToken]);
exit;
} else {
http_response_code(401);
echo json_encode(['error' => 'Invalid credentials']);
exit;
}
}
// Handle secured resource request
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['token'])) {
$token = $_GET['token'];
$decodedToken = verifyToken($token);
if ($decodedToken) {
echo json_encode(['message' => 'Access granted', 'user' => $decodedToken]);
exit;
} else {
http_response_code(401);
echo json_encode(['error' => 'Invalid token']);
exit;
}
}
- Frontend: Create
index.html
Open index.html
in the frontend
directory and set up the HTML structure with a login form and a secured resource display:
<!DOCTYPE html>
<html>
<head>
<title>JWT Authentication Example</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<h1 class="mb-4">JWT Authentication Example</h1>
<!-- Login Form -->
<form id="loginForm">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" required>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<!-- Secured Resource Display -->
<div id="securedResource" class="mt-5" style="display: none;">
<h3>Secured Resource</h3>
<p id="resourceContent"></p>
</div>
</div>
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.bundle.min.js"></script>
<script>
// Handle login form submission
$('#loginForm').submit(function(event) {
event.preventDefault();
const username = $('#username').val();
const password = $('#password').val();
// Send login request to backend
$.ajax({
url: '../backend/index.php',
method: 'POST',
data: { username: username, password: password },
dataType: 'json',
success: function(response) {
// Store the token in local storage
localStorage.setItem('token', response.token);
// Hide login form and show secured resource display
$('#loginForm').hide();
$('#securedResource').show();
// Fetch secured resource
fetchResource();
},
error: function(error) {
alert('Login failed: ' + error.responseJSON.error);
}
});
});
// Fetch the secured resource from the backend
function fetchResource() {
const token = localStorage.getItem('token');
// Send secured resource request to backend
$.ajax({
url: '../backend/index.php',
method: 'GET',
data: { token: token },
dataType: 'json',
success: function(response) {
$('#resourceContent').text(JSON.stringify(response, null, 2));
},
error: function(error) {
alert('Access denied: ' + error.responseJSON.error);
}
});
}
// Check if token exists and show secured resource display if so
const token = localStorage.getItem('token');
if (token) {
$('#loginForm').hide();
$('#securedResource').show();
fetchResource();
}
</script>
</body>
</html>
Running the Example
To run the example, open two separate terminals, one for the backend and one for the frontend.
- In the backend terminal, navigate to the
backend
directory and start the PHP development server:
php -S localhost:8000
In the frontend terminal, navigate to the frontend
directory and start a simple HTTP server:
php -S localhost:8080
Now, open your browser and visit http://localhost:8080
to see the example in action. The frontend will display a login form, and upon successful login, it will show the secured resource response obtained from the backend, demonstrating JWT-based authentication.