This example demonstrates a complete session-based authentication implementation using Stilmark Base's Session, Auth, AuthMiddleware, and CsrfMiddleware classes.
<?php
use Stilmark\Base\Auth;
use Stilmark\Base\Request;
use Stilmark\Base\Render;
use Stilmark\Base\Session;
// Route: GET /login
function loginPage(Request $request)
{
// Generate CSRF token for the login form
$csrfToken = $request->generateCsrfToken();
// Get flash messages
$error = Session::getFlash('error');
$success = Session::getFlash('success');
// Render login page (example with inline HTML)
?>
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<?php if ($error): ?>
<div class="error"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="success"><?= htmlspecialchars($success) ?></div>
<?php endif; ?>
<h2>Login with Google</h2>
<form method="POST" action="/auth/google">
<input type="hidden" name="_token" value="<?= $csrfToken ?>">
<button type="submit">Sign in with Google</button>
</form>
</body>
</html>
<?php
}
// Route: POST /auth/google (initiate OAuth)
function initiateGoogleAuth(Request $request)
{
// Validate CSRF token
if (!$request->validateCsrfToken()) {
Session::flash('error', 'Invalid CSRF token');
header('Location: /login');
exit;
}
$auth = new Auth('google');
$auth->callout(); // Redirects to Google
}
// Route: GET /auth/google/callback
function handleGoogleCallback(Request $request)
{
$auth = new Auth('google');
try {
$result = $auth->callback($request);
if ($result['status'] === 'success') {
// Session is already set up by Auth::callback()
// with regenerated session ID and timestamps
Session::flash('success', 'Login successful!');
header('Location: /dashboard');
exit;
} else {
Session::flash('error', $result['message'] ?? 'Login failed');
header('Location: /login');
exit;
}
} catch (Exception $e) {
Session::flash('error', 'Authentication error: ' . $e->getMessage());
header('Location: /login');
exit;
}
}
<?php
// src/Middleware/AppAuthMiddleware.php
namespace App\Middleware;
use Stilmark\Base\AuthMiddleware;
use Stilmark\Base\Env;
class AppAuthMiddleware extends AuthMiddleware
{
private $db;
public function __construct($db = null)
{
parent::__construct(
authSessionKey: Env::get('SESSION_AUTH_NAME', 'auth'),
idleTimeout: (int) Env::get('SESSION_IDLE_TIMEOUT', 1800),
absoluteTimeout: (int) Env::get('SESSION_ABSOLUTE_TIMEOUT', 28800)
);
$this->db = $db;
}
/**
* Custom validation: Check if user exists and is active
*/
protected function validateSession(array $sessionData): bool
{
// First, call parent validation
if (!parent::validateSession($sessionData)) {
return false;
}
// If no database connection, skip database validation
if (!$this->db) {
return true;
}
// Get user email from session
$userEmail = $sessionData['user']['email'] ?? null;
if (!$userEmail) {
return false;
}
// Check if user exists and is active in database
$stmt = $this->db->prepare("SELECT id, status FROM users WHERE email = ?");
$stmt->execute([$userEmail]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user || $user['status'] !== 'active') {
$this->clearAuthSession();
return false;
}
return true;
}
}
<?php
use Stilmark\Base\Request;
use Stilmark\Base\Render;
use Stilmark\Base\Session;
use App\Middleware\AppAuthMiddleware;
// Route: GET /dashboard
function dashboard(Request $request, $db)
{
// Create auth middleware with database connection
$authMiddleware = new AppAuthMiddleware($db);
// Validate authentication
if (!$authMiddleware->handle()) {
Session::flash('error', 'Please login to continue');
header('Location: /login');
exit;
}
// Get user data from session
$authData = Session::get('auth');
$user = $authData['user'] ?? null;
// Generate CSRF token for forms on this page
$csrfToken = $request->generateCsrfToken();
?>
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
</head>
<body>
<h1>Welcome, <?= htmlspecialchars($user['name'] ?? 'User') ?>!</h1>
<p>Email: <?= htmlspecialchars($user['email'] ?? '') ?></p>
<h2>Session Info</h2>
<ul>
<li>Provider: <?= htmlspecialchars($authData['provider'] ?? 'N/A') ?></li>
<li>Login Time: <?= date('Y-m-d H:i:s', $authData['auth_time'] ?? 0) ?></li>
<li>Last Activity: <?= date('Y-m-d H:i:s', Session::get('last_activity', 0)) ?></li>
</ul>
<form method="POST" action="/logout">
<input type="hidden" name="_token" value="<?= $csrfToken ?>">
<button type="submit">Logout</button>
</form>
</body>
</html>
<?php
}
<?php
use Stilmark\Base\Router;
use Stilmark\Base\CsrfMiddleware;
use Stilmark\Base\Env;
$router = new Router();
// Create CSRF middleware
$allowedOrigins = explode(',', Env::get('CSRF_ALLOWED_ORIGINS', ''));
$csrfMiddleware = new CsrfMiddleware($allowedOrigins);
// Apply CSRF protection to all POST/PUT/PATCH/DELETE routes
$router->post('/auth/google', 'initiateGoogleAuth', [$csrfMiddleware]);
$router->post('/logout', 'handleLogout', [$csrfMiddleware]);
$router->post('/api/users', 'createUser', [$csrfMiddleware]);
$router->delete('/api/users/:id', 'deleteUser', [$csrfMiddleware]);
<?php
use Stilmark\Base\Request;
use Stilmark\Base\Render;
function createUser(Request $request)
{
// Manual CSRF validation (if not using middleware)
if ($request->isUnsafeMethod() && !$request->validateCsrfToken()) {
Render::json(['error' => 'CSRF validation failed'], 403);
exit;
}
// Process user creation
$data = $request->json();
// ... create user logic
Render::json(['success' => true, 'user_id' => 123]);
}