DALT.PHP
Guides

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 migrate

If 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/auth

Register 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 serve

Register a User

  1. Visit http://localhost:8000/register
  2. Enter email and password
  3. Click Register
  4. 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

  1. Visit http://localhost:8000/login
  2. Enter your credentials
  3. 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

On this page