Adding Authentication
Implement secure user registration and login
Learn how to add user authentication to your DALT.PHP application with secure password hashing, session management, and protected routes.
What You'll Build
A complete authentication system with:
- User registration with validation
- Secure login with password verification
- Session-based authentication
- Protected routes with Auth middleware
- Logout functionality
Time Required: 25-35 minutes
Step 1: Users Table Already Exists
DALT.PHP comes with a users table migration. Check if it's already run:
# Check if users table exists
php artisan migrateIf not already created, the migration creates:
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);Step 2: Create Auth Controllers
Create Directory
mkdir -p app/Http/controllers/authRegister Form (GET /register)
Create app/Http/controllers/auth/register.php:
<?php
view('auth/register.view.php', [
'title' => 'Register'
]);Register Handler (POST /register)
Create app/Http/controllers/auth/register-post.php:
<?php
$db = App::resolve(Core\Database::class);
// Validate
$errors = [];
if (empty($_POST['email']) || !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Valid email is required';
}
if (empty($_POST['password']) || strlen($_POST['password']) < 8) {
$errors['password'] = 'Password must be at least 8 characters';
}
if ($_POST['password'] !== $_POST['password_confirmation']) {
$errors['password_confirmation'] = 'Passwords do not match';
}
// Check if email exists
$existing = $db->query('SELECT id FROM users WHERE email = ?', [$_POST['email']])->find();
if ($existing) {
$errors['email'] = 'Email already registered';
}
if (!empty($errors)) {
view('auth/register.view.php', ['errors' => $errors, 'old' => $_POST]);
exit;
}
// Hash password and create user
$db->query(
'INSERT INTO users (email, password) VALUES (?, ?)',
[$_POST['email'], password_hash($_POST['password'], PASSWORD_BCRYPT)]
);
// Auto-login after registration
$user = $db->query('SELECT * FROM users WHERE email = ?', [$_POST['email']])->find();
Core\Session::put('user', ['id' => $user['id'], 'email' => $user['email']]);
Core\Session::flash('success', 'Account created successfully!');
header('Location: /');
exit;Login Form (GET /login)
Create app/Http/controllers/auth/login.php:
<?php
view('auth/login.view.php', [
'title' => 'Login'
]);Login Handler (POST /login)
Create app/Http/controllers/auth/login-post.php:
<?php
$db = App::resolve(Core\Database::class);
// Find user
$user = $db->query('SELECT * FROM users WHERE email = ?', [$_POST['email']])->find();
// Verify password
if (!$user || !password_verify($_POST['password'], $user['password'])) {
view('auth/login.view.php', [
'errors' => ['email' => 'Invalid credentials'],
'old' => $_POST
]);
exit;
}
// Create session
Core\Session::put('user', ['id' => $user['id'], 'email' => $user['email']]);
Core\Session::flash('success', 'Welcome back!');
header('Location: /');
exit;Logout Handler (POST /logout)
Create app/Http/controllers/auth/logout.php:
<?php
Core\Session::destroy();
Core\Session::flash('success', 'Logged out successfully');
header('Location: /');
exit;Step 3: Create Views
Register View
Create resources/views/auth/register.view.php:
<!DOCTYPE html>
<html>
<head>
<title>Register</title>
</head>
<body>
<h1>Register</h1>
<form method="POST" action="/register">
<div>
<label>Email:</label>
<input type="email" name="email" value="<?= htmlspecialchars($old['email'] ?? '') ?>" required>
<?php if (isset($errors['email'])): ?>
<p style="color: red;"><?= $errors['email'] ?></p>
<?php endif; ?>
</div>
<div>
<label>Password:</label>
<input type="password" name="password" required>
<?php if (isset($errors['password'])): ?>
<p style="color: red;"><?= $errors['password'] ?></p>
<?php endif; ?>
</div>
<div>
<label>Confirm Password:</label>
<input type="password" name="password_confirmation" required>
<?php if (isset($errors['password_confirmation'])): ?>
<p style="color: red;"><?= $errors['password_confirmation'] ?></p>
<?php endif; ?>
</div>
<button type="submit">Register</button>
</form>
<p>Already have an account? <a href="/login">Login</a></p>
</body>
</html>Login View
Create resources/views/auth/login.view.php:
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form method="POST" action="/login">
<div>
<label>Email:</label>
<input type="email" name="email" value="<?= htmlspecialchars($old['email'] ?? '') ?>" required>
</div>
<div>
<label>Password:</label>
<input type="password" name="password" required>
</div>
<?php if (isset($errors['email'])): ?>
<p style="color: red;"><?= $errors['email'] ?></p>
<?php endif; ?>
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="/register">Register</a></p>
</body>
</html>Step 4: Add Routes
Add auth routes to routes/routes.php:
// Auth routes
$router->get('/register', 'auth/register.php')->only('guest');
$router->post('/register', 'auth/register-post.php')->only('guest');
$router->get('/login', 'auth/login.php')->only('guest');
$router->post('/login', 'auth/login-post.php')->only('guest');
$router->post('/logout', 'auth/logout.php')->only('auth');Step 5: Protect Routes
Protect routes that require authentication:
// Protected routes
$router->get('/dashboard', 'dashboard.php')->only('auth');
$router->get('/posts/create', 'posts/create.php')->only('auth');
$router->post('/posts', 'posts/store.php')->only('auth');Step 6: Test Authentication
Start Server
php artisan serveRegister a User
- Visit http://localhost:8000/register
- Enter email and password
- Click Register
- You should be logged in automatically
Logout
Add logout button to your views:
<?php if (Core\Session::has('user')): ?>
<form method="POST" action="/logout" style="display: inline;">
<button type="submit">Logout</button>
</form>
<?php endif; ?>Login Again
- Visit http://localhost:8000/login
- Enter your credentials
- Click Login
What You Learned
1. Password Hashing
// NEVER store plain text passwords!
$hash = password_hash($password, PASSWORD_BCRYPT);
// Verify password
if (password_verify($password, $hash)) {
// Correct password
}2. Session Management
// Store user in session
Core\Session::put('user', ['id' => $user['id'], 'email' => $user['email']]);
// Check if logged in
if (Core\Session::has('user')) {
// User is authenticated
}
// Destroy session
Core\Session::destroy();3. Middleware Protection
// Only authenticated users
$router->get('/dashboard', 'dashboard.php')->only('auth');
// Only guests (not logged in)
$router->get('/login', 'auth/login.php')->only('guest');4. Input Validation
// Email validation
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Valid email required';
}
// Password length
if (strlen($_POST['password']) < 8) {
$errors['password'] = 'Password must be at least 8 characters';
}Security Best Practices
Your authentication system implements:
✅ Password hashing with bcrypt ✅ Email validation before registration ✅ Unique email constraint in database ✅ Password confirmation during registration ✅ Session-based auth (not cookies) ✅ Middleware protection for routes ✅ XSS prevention with htmlspecialchars
Congratulations! You've implemented secure authentication with password hashing, session management, and protected routes.
Next Steps
- Building a Blog - Add auth to blog posts
- Building a REST API - Add API authentication
- Working with Database - Advanced queries