mini\Auth
namespace
Auth - Authentication System
Philosophy
Mini's auth system is framework-agnostic by design. We don't prescribe how you authenticate users—whether it's sessions, JWTs, API keys, or something custom. Instead, we provide a clean facade with convenience methods that delegate to your implementation.
Key Principles:
- Your implementation, our convenience - You provide
AuthInterface, we provideauth()facade - No database coupling - Auth doesn't assume how you store users
- Minimal abstraction - Direct access to your implementation when needed
- Fluent API - Chain authorization checks:
auth()->requireLogin()->requireRole('admin')
Setup
Auth requires configuration. Create _config/mini/Auth/AuthInterface.php:
<?php
// _config/mini/Auth/AuthInterface.php
return new App\Auth\SessionAuth();
Implementing AuthInterface
<?php
namespace App\Auth;
use mini\Auth\AuthInterface;
class SessionAuth implements AuthInterface
{
public function isAuthenticated(): bool
{
return isset($_SESSION['user_id']);
}
public function getUserId(): mixed
{
return $_SESSION['user_id'] ?? null;
}
public function getClaim(string $name): mixed
{
return $_SESSION['user'][$name] ?? null;
}
public function hasRole(string $role): bool
{
$userRoles = $_SESSION['user']['roles'] ?? [];
return in_array($role, $userRoles);
}
public function hasPermission(string $permission): bool
{
$permissions = $_SESSION['user']['permissions'] ?? [];
return in_array($permission, $permissions);
}
}
Common Usage Examples
Basic Authentication Check
// Check if user is logged in
if (auth()->isAuthenticated()) {
echo "Welcome back!";
}
// Get current user ID
$userId = auth()->getUserId();
// Get user claims
$email = auth()->getClaim('email');
$name = auth()->getClaim('name');
Route Protection
<?php
// _routes/admin/dashboard.php
// Require login - throws AccessDeniedException if not authenticated
// Framework catches exception and shows _errors/401.php
auth()->requireLogin();
// Or require specific role
auth()->requireRole('admin');
// Or require permission
auth()->requirePermission('edit_posts');
// Chain requirements
auth()->requireLogin()
->requireRole('editor')
->requirePermission('publish_posts');
// Continue with protected logic
$dashboard = loadDashboardData();
echo render('admin/dashboard', ['data' => $dashboard]);
Role-Based Access
// Check roles
if (auth()->hasRole('admin')) {
// Show admin panel
}
if (auth()->hasRole('editor') || auth()->hasRole('admin')) {
// Show editor tools
}
Permission-Based Access
// Check permissions
if (auth()->hasPermission('delete_users')) {
echo '<button>Delete User</button>';
}
if (auth()->hasPermission('edit_posts')) {
// Show edit button
}
Login/Logout Flow
<?php
// _routes/login.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$user = db()->queryOne(
"SELECT * FROM users WHERE email = ? AND password = ?",
[$_POST['email'], password_hash($_POST['password'], PASSWORD_DEFAULT)]
);
if ($user) {
session();
$_SESSION['user_id'] = $user['id'];
$_SESSION['user'] = [
'email' => $user['email'],
'name' => $user['name'],
'roles' => explode(',', $user['roles']),
'permissions' => explode(',', $user['permissions'])
];
redirect('/dashboard');
}
}
<?php
// _routes/logout.php
session();
session_destroy();
redirect('/');
API Route Protection
<?php
// _routes/api/protected.php
// Framework will catch exception and show _errors/401.php
auth()->requireLogin();
// Protected API logic
header('Content-Type: application/json');
echo json_encode(['data' => $secretData]);
Custom Error Pages
Create _errors/401.php for unauthorized access:
<?php
// _errors/401.php
header('Content-Type: application/json');
echo json_encode([
'error' => 'Unauthorized',
'message' => 'Please log in to access this resource'
]);
Create _errors/403.php for forbidden access:
<?php
// _errors/403.php
header('Content-Type: application/json');
echo json_encode([
'error' => 'Forbidden',
'message' => 'You do not have permission to access this resource'
]);
Direct Implementation Access
When you need more than the facade provides:
$authImpl = auth()->getImplementation();
// Call custom methods on your implementation
if (method_exists($authImpl, 'refreshToken')) {
$authImpl->refreshToken();
}
Advanced: JWT Authentication
<?php
// _config/mini/Auth/AuthInterface.php
return new App\Auth\JWTAuth($_ENV['JWT_SECRET']);
<?php
namespace App\Auth;
use mini\Auth\AuthInterface;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JWTAuth implements AuthInterface
{
private ?array $claims = null;
public function __construct(private string $secret) {}
private function getClaims(): ?array
{
if ($this->claims !== null) {
return $this->claims;
}
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$token = str_replace('Bearer ', '', $token);
if (!$token) {
return null;
}
try {
$decoded = JWT::decode($token, new Key($this->secret, 'HS256'));
$this->claims = (array) $decoded;
return $this->claims;
} catch (\Exception $e) {
return null;
}
}
public function isAuthenticated(): bool
{
return $this->getClaims() !== null;
}
public function getUserId(): mixed
{
return $this->getClaim('sub');
}
public function getClaim(string $name): mixed
{
return $this->getClaims()[$name] ?? null;
}
public function hasRole(string $role): bool
{
$roles = $this->getClaim('roles') ?? [];
return in_array($role, $roles);
}
public function hasPermission(string $permission): bool
{
$permissions = $this->getClaim('permissions') ?? [];
return in_array($permission, $permissions);
}
}
Configuration
Config File: _config/mini/Auth/AuthInterface.php (required)
Environment Variables: None - auth is entirely custom
Overriding the Service
Auth uses two services:
mini\Auth\Auth(facade) - Automatically registered as Singletonmini\Auth\AuthInterface(your implementation) - You provide via config
To use a different facade (advanced):
// _config/mini/Auth/Auth.php
return new App\Auth\CustomAuthFacade();
Error Handling
When auth requirements aren't met, Mini throws \mini\Http\AccessDeniedException:
- 401 Unauthorized - User not authenticated
- 403 Forbidden - User authenticated but lacks permission/role
The framework automatically handles these exceptions and shows appropriate error pages.