This document covers everything you need to know about Simple-Auth-Template — from project structure and database setup, to how each file works and how to extend the system.
- Overview
- Repository Structure
- File Reference
- Database Schema
- Configuration
- Auth Flow (Detailed)
- Core Functions
- Pages & Routes
- Session Management
- Security Practices
- UI & Styling
- Extending the Template
- Common Errors & Fixes
- FAQ
Simple-Auth-Template is a plain PHP + MySQL authentication starter kit. It provides the minimum viable auth system — register, login, session guard, and logout — in a clean folder structure that's easy to read, customize, and scale.
It does not use any PHP framework. Everything is written in procedural PHP with a lightweight MVC-lite organization, making it beginner-friendly while still being structured enough for real projects.
Simple-Auth-Template/
│
├── public/ # Entry point — all browser-accessible files
│ ├── index.php # Landing / redirect page
│ ├── login.php # Login page
│ ├── register.php # Registration page
│ ├── dashboard.php # Protected page (requires login)
│ ├── logout.php # Destroys session and redirects
│ └── assets/
│ ├── css/ # Stylesheets
│ ├── js/ # JavaScript files
│ └── img/ # Images / icons
│
├── includes/ # Core backend logic (not browser-accessible)
│ ├── db.php # Database connection
│ ├── auth.php # Auth functions (login, register, guard)
│ ├── config.php # App configuration (DB credentials, constants)
│ └── functions.php # General helper functions
│
├── templates/ # Shared HTML partials
│ ├── header.php # HTML head + navbar
│ └── footer.php # Closing tags + scripts
│
├── database/
│ └── schema.sql # MySQL table definitions
│
├── README.md
├── DOCUMENTATION.md
├── LICENSE
└── .gitignore
Note: Only the
public/folder should be the web root. Theincludes/andtemplates/folders are intentionally kept outside to prevent direct browser access.
Stores all global configuration constants. This is the first file you should edit after cloning.
<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'simple_auth');
define('BASE_URL', 'http://localhost/Simple-Auth-Template/public');
?>Handles the MySQL database connection using mysqli. It uses the constants defined in config.php.
<?php
require_once 'config.php';
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
?>The heart of the system. Contains all authentication logic:
register_user($username, $email, $password)— validates and saves a new userlogin_user($email, $password)— checks credentials and starts a sessionis_logged_in()— returnstrueif a valid session existsauth_guard()— redirects to login if user is not authenticatedlogout_user()— destroys the session and redirects
General-purpose helper functions used across the app. Examples:
sanitize($input)— strips and escapes user inputredirect($url)— shorthand forheader("Location: ...")+exitset_flash($type, $message)— stores a one-time session messageget_flash($type)— retrieves and clears the flash message
Included at the top of every page. Contains the <head> block, meta tags, CSS links, and the navigation bar. Modify this to change the global layout or add Bootstrap/Font Awesome CDN links.
Included at the bottom of every page. Contains closing </body> and </html> tags, and any global JS script tags.
The system uses a single users table.
CREATE DATABASE IF NOT EXISTS simple_auth;
USE simple_auth;
CREATE TABLE users (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);| Column | Type | Description |
|---|---|---|
id |
INT, PK, AUTO_INCREMENT | Unique identifier for each user |
username |
VARCHAR(100) | Display name chosen during registration |
email |
VARCHAR(150), UNIQUE | Used as the login identifier |
password |
VARCHAR(255) | Bcrypt-hashed password (never plain text) |
created_at |
TIMESTAMP | Auto-set when the record is created |
Never store plain text passwords. Simple-Auth-Template uses PHP's
password_hash()with thePASSWORD_BCRYPTalgorithm by default.
After cloning, open includes/config.php and update the following:
| Constant | Default | Description |
|---|---|---|
DB_HOST |
localhost |
Your MySQL server host |
DB_USER |
root |
MySQL username |
DB_PASS |
(empty) | MySQL password |
DB_NAME |
simple_auth |
Name of your database |
BASE_URL |
http://localhost/... |
Full base URL of the project |
User fills register form
↓
Client-side validation (v2+)
↓
Server receives POST data
↓
sanitize() cleans all inputs
↓
Check if email already exists in DB
↓ (if exists → show error)
password_hash() hashes the password
↓
INSERT new user into `users` table
↓
Redirect to login with success message
User fills login form
↓
Server receives POST data
↓
sanitize() cleans inputs
↓
SELECT user WHERE email = input
↓ (if not found → show error)
password_verify() checks hash against input
↓ (if mismatch → show error)
$_SESSION['user_id'] and ['username'] are set
↓
Redirect to dashboard
User requests a protected page (e.g. dashboard.php)
↓
auth_guard() is called at the top of the page
↓
Checks if $_SESSION['user_id'] is set
↓ (if not set → redirect to login.php)
Page loads normally
User clicks logout
↓
logout.php is loaded
↓
session_unset() clears session variables
↓
session_destroy() destroys the session
↓
Redirect to login.php
Registers a new user. Returns true on success or an error string on failure.
$result = register_user('john', 'john@email.com', 'secret123');
if ($result === true) {
redirect(BASE_URL . '/login.php');
} else {
echo $result; // Error message
}Verifies credentials and starts a session. Returns true on success or an error string.
$result = login_user('john@email.com', 'secret123');
if ($result === true) {
redirect(BASE_URL . '/dashboard.php');
}Call this at the very top of any page that requires a logged-in user. If the session is missing, it redirects immediately.
<?php
require_once '../includes/auth.php';
auth_guard(); // Redirects to login if not authenticated
?>Returns a boolean. Useful for conditionally showing UI elements (e.g. hiding the login button if already logged in).
if (is_logged_in()) {
echo "Welcome back!";
}| File | URL | Access | Description |
|---|---|---|---|
index.php |
/ |
Public | Landing page, redirects based on session |
register.php |
/register.php |
Public | New user registration form |
login.php |
/login.php |
Public | Login form |
dashboard.php |
/dashboard.php |
Protected | Main page after login |
logout.php |
/logout.php |
Protected | Destroys session, redirects to login |
Sessions are PHP native ($_SESSION). The following keys are used:
| Key | Set When | Value |
|---|---|---|
$_SESSION['user_id'] |
Login success | User's id from DB |
$_SESSION['username'] |
Login success | User's username from DB |
$_SESSION['flash'] |
After form actions | Temporary status messages |
Sessions are destroyed completely on logout via session_unset() + session_destroy().
Simple-Auth-Template follows these security principles out of the box:
| Practice | How It's Applied |
|---|---|
| Password Hashing | password_hash() with PASSWORD_BCRYPT |
| Input Sanitization | sanitize() wraps htmlspecialchars() + trim() |
| No Plain Text Passwords | Passwords are never stored or logged as plain text |
| Session-based Auth | No tokens stored in URLs or cookies manually |
| Protected Routes | auth_guard() must be called on every protected page |
- CSRF token protection on forms
- Rate limiting on login attempts
- Prepared statements (recommended upgrade — replace
mysqli_querywithmysqli_prepare) - HTTPS enforcement
Recommended: Switch all raw
mysqli_query()calls to prepared statements before deploying to production. This prevents SQL injection.
The base template uses plain HTML and CSS. To upgrade the UI:
In templates/header.php, add inside <head>:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">And before </body> in templates/footer.php:
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>In templates/header.php, add inside <head>:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">- Create
public/your-page.php - Add
auth_guard()at the top - Include header and footer templates
<?php
require_once '../includes/auth.php';
auth_guard();
require_once '../templates/header.php';
?>
<h1>Your Page</h1>
<?php require_once '../templates/footer.php'; ?>- Run the ALTER query in phpMyAdmin or CLI:
ALTER TABLE users ADD COLUMN profile_pic VARCHAR(255) DEFAULT NULL;- Update
register_user()inauth.phpto include the new field in the INSERT query.
Add a role column to the users table:
ALTER TABLE users ADD COLUMN role ENUM('user', 'admin') DEFAULT 'user';Then create a role guard function in auth.php:
function admin_guard() {
auth_guard();
if ($_SESSION['role'] !== 'admin') {
redirect(BASE_URL . '/dashboard.php');
}
}| Error | Likely Cause | Fix |
|---|---|---|
Connection failed |
Wrong DB credentials | Check config.php values |
| Blank page after login | Session not starting | Add session_start() at top of auth.php |
| Redirect loop on dashboard | auth_guard() misconfigured |
Make sure session_start() runs before the guard check |
Call to undefined function |
Missing require_once |
Ensure auth.php is included on the page |
| Password always wrong | Hashing issue | Make sure you're hashing on register, not on login |
Q: Can I use this with a framework like Laravel? Yes, but you'd essentially be replacing most of the logic. The roadmap includes an optional Laravel conversion in v4 for those who want to migrate.
Q: Is this safe for production? The core is a solid starting point, but before going live you should add CSRF protection, use prepared statements everywhere, and enforce HTTPS. See the Security Practices section.
Q: Can I add OAuth (Google/GitHub login)?
Not out of the box, but it's a great v3/v4 contribution idea. You'd add a provider and provider_id column to the users table and handle the OAuth callback in a new file.
Q: Why no framework? By design. Simple-Auth-Template is meant to be readable and educational. Anyone who knows basic PHP can understand and modify it without needing to learn a framework first.
Documentation maintained by the Simple-Auth-Template contributors. For issues or suggestions, open a GitHub Issue.