Authentication
Authentication
This document describes how to configure and use the authentication system in the Hazaar Framework. The system is designed to be highly flexible, decoupling how you check a password (Adapter) from where you store the session (Backend) and how the client remembers the session (Transport).
Configuration
The authentication configuration is located in app/configs/app.php under the auth key.
Basic Configuration Example
// app/configs/app.php
'auth' => [
'adapter' => \App\Model\Auth::class,
'backend' => \Hazaar\Auth\Session\Backend\Cache::class,
'transport' => \Hazaar\Auth\Session\Transport\Cookie::class,
'cache' => [
'adapter' => 'file',
],
],{
"auth": {
"adapter": "App\\Model\\Auth",
"backend": "Hazaar\\Auth\\Session\\Backend\\Cache",
"transport": "Hazaar\\Auth\\Session\\Transport\\Cookie",
"cache": {
"adapter": "file"
}
}
}[auth]
adapter = "App\\Model\\Auth"
backend = "Hazaar\\Auth\\Session\\Backend\\Cache"
transport = "Hazaar\\Auth\\Session\\Transport\\Cookie"
[auth.cache]
adapter = "file"The configuration consists of three main components:
- Adapter: The logic that connects to your user database. It is responsible for validating credentials and retrieving current user details.
- Backend: The storage mechanism for the session/token. This decides if the session is stored in a file, in memory (Redis/Memcached), or inside the token itself (JWT).
- Transport: How the session ID or token is transferred between the client and server. This is typically via an HTTP Cookie or an HTTP Header (like
Authorization).
Options for each component are defined in a property that matches the lower-case class name of the component (e.g., cache for the Cache backend, jwt for the JWT backend).
Defining an Adapter
To create an authentication adapter, you must extend Hazaar\Auth\Adapter. This class is the bridge between the framework's authentication system and your user data source (e.g., a MySQL database, LDAP server, or API).
The primary responsibility of the adapter is to implement the queryAuth method. This method acts as a lookup function: given a username (identity), it returns the stored password hash (credential) and user details. The framework then handles the password verification logic securely.
Example Adapter (app/models/Auth.php)
<?php
declare(strict_types=1);
namespace App\Model;
use Hazaar\Auth\Adapter;
class Auth extends Adapter
{
/**
* Authenticate a user.
*
* @param string $identity The username or email provided by the user during login.
* @return array|bool Returns user data array on success, or false if the user is not found.
*/
public function queryAuth(string $identity): array|bool
{
// Example logic:
// 1. Query your database for the user with the given $identity.
// $user = \App\Model\User::find(['username' => $identity]);
// 2. If not found, return false.
// 3. Return an array structure expected by the framework.
// It is CRITICAL to return the 'credential' key. This is the hashed password
// from your database. The framework will hash the input password and compare it
// to this value.
return [
'identity' => $identity,
// getCredentialHash() is a helper to generate a hash using the configured method
'credential' => $this->getCredentialHash('password123'),
'data' => [
'id' => 1,
'name' => 'Example User',
'email' => '[email protected]',
'role' => 'admin',
],
];
}
}Usage (Login & Logout)
Authentication is typically handled in your controllers.
Logging In (Main.php / Api.php)
To log a user in, use $this->session->authenticate($username, $password).
public function login(): ?Response
{
if ($this->request->isPost()) {
$username = $this->request->get('username');
$password = $this->request->get('password');
// Attempt authentication
$result = $this->session->authenticate($username, $password);
if ($result->success) {
return $this->response->redirect('/dashboard');
}
$this->view->set('error', 'Invalid username or password');
}
$this->view('login');
}Logging Out
To log a user out, use $this->session->logout().
public function logout(): Response
{
$this->session->logout();
return $this->response->redirect('/');
}Accessing Authenticated User
You can access the authenticated user's data using the auth attribute from the request or directly via $this->session.
public function init(): void
{
// Pass authenticated user data to the view
$this->view->set('user', $this->request->getAttribute('auth'));
}
public function dashboard(): void
{
// Check if user is authenticated
if (!$this->request->hasAttribute('auth')) {
// Handle unauthenticated state
}
}Backends
The backend determines how the session data or authentication token is stored server-side (or client-side in the case of JWT).
1. PHPSession
This is the standard, default PHP session handler. It uses the $_SESSION superglobal and PHP's built-in session management mechanism.
Best for: Traditional monolithic web applications where the server handles HTML rendering and state.
Class: Hazaar\Auth\Session\Backend\PHPSessionConfig Key: phpsession
Configuration Options
name: The session name (passed tosession_name()). Use this to isolate your app's session cookies.timeout: Session timeout in seconds (passed tosession.gc_maxlifetime).
'auth' => [
'backend' => \Hazaar\Auth\Session\Backend\PHPSession::class,
'phpsession' => [
'name' => 'MYAPP_SESSION',
'timeout' => 3600,
],
],2. JWT (JSON Web Token)
JWTs allow for stateless authentication. Instead of storing session data on the server, the data is encrypted and signed into a token that is sent to the client. When the client returns the token, the server verifies the signature to trust the data.
Best for: REST APIs, Microservices, and Mobile Applications where you want to avoid storing session state on the server or need to share authentication across multiple domains/services.
Class: Hazaar\Auth\Session\Backend\JWTConfig Key: jwt
Configuration Options
alg: Signing algorithm (default:HS256).issuer: The issuer string to verify token origin (default: current app URL).expire: Token expiration time in seconds (default:3600). Short expirations are recommended.refresh: Refresh token expiration time in seconds (default:86400).passphrase: The secret key used to sign the token. Change this to a strong, random string.fingerprintKeys: Array of$_SERVERkeys to bind to the token (default:['HTTP_USER_AGENT', 'HTTP_ACCEPT']). This helps prevent token theft by ensuring the token is used by the same type of client that requested it.
'auth' => [
'backend' => \Hazaar\Auth\Session\Backend\JWT::class,
'jwt' => [
'passphrase' => 'super-secret-key-CHANGE-ME',
'expire' => 7200,
],
],3. Cache
This backend uses the Hazaar Cache system (Redis, Memcached, File, etc.) to store session data. It offers better performance and control than standard PHP sessions, especially for distributed systems where multiple servers need access to the same session data.
Best for: High-performance web applications or load-balanced environments where you need centralized session storage but want to avoid the limitations of file-based PHP sessions.
Class: Hazaar\Auth\Session\Backend\CacheConfig Key: cache
Configuration Options
adapter: Cache adapter to use (e.g.,file,redis,memcached- default:file).usePragma: (default:false).ttl: Time to live in seconds (default:3600).path: Storage path if using thefileadapter (default:runtime/cache/sessions).
'auth' => [
'backend' => \Hazaar\Auth\Session\Backend\Cache::class,
'cache' => [
'adapter' => 'redis',
'ttl' => 3600,
],
],Transports
The transport determines how the authentication token or session ID is exchanged between the client and the server for each request.
1. Cookie
Stores the session ID or token in a standard HTTP cookie. The browser automatically handles sending this cookie with every request to the domain.
Best for: Traditional web applications and websites. It is the most secure option for browsers when configured with HttpOnly and Secure flags, as it protects the token from XSS attacks.
Class: Hazaar\Auth\Session\Transport\CookieConfig Key: cookie
Configuration Options
cookie_name: Name of the cookie (default:hazaar-auth-token).expires: Cookie expiration timestamp (default:0which means it is a session cookie that expires when the browser closes).path: Cookie path (default:/).domain: Cookie domain. Set this if you need the cookie to be available on subdomains.secure: Iftrue, the cookie is only sent over HTTPS (default:true).httponly: Iftrue, the cookie cannot be accessed by JavaScript, preventing XSS token theft (default:true).samesite: SameSite policy to prevent CSRF (default:Lax).
'auth' => [
'transport' => \Hazaar\Auth\Session\Transport\Cookie::class,
'cookie' => [
'cookie_name' => 'myapp_auth',
'secure' => true,
'samesite' => 'Strict',
],
],2. Header
Sends the token in an HTTP request header (typically Authorization). This requires the client (e.g., your JavaScript frontend or mobile app) to manually store the token and attach it to every API request.
Best for: REST APIs, Single Page Applications (SPAs), and Mobile Apps where you are making AJAX/Fetch requests and cannot rely on cookies (e.g., cross-domain requests).
Class: Hazaar\Auth\Session\Transport\HeaderConfig Key: header
Configuration Options
name: The name of the header to check (default:Authorization).prefix: The prefix expected before the token value (default:Bearer).
'auth' => [
'transport' => \Hazaar\Auth\Session\Transport\Header::class,
'header' => [
'name' => 'X-Api-Token',
// Resulting Setup: "X-Api-Token: Token <your-token>"
'prefix' => 'Token',
],
],Extending Functionality
The Hazaar Framework authentication system is designed to be completely modular. If the built-in backends or transports do not meet your needs, you can easily implement your own.
Custom Session Backend
To create a custom backend (e.g., to store sessions in a NoSQL database like MongoDB or DynamoDB), create a class that implements the Hazaar\Auth\Interface\SessionBackend interface.
<?php
namespace App\Auth\Backend;
use Hazaar\Auth\Interface\SessionBackend;
class MongoDBSession implements SessionBackend
{
private array $config;
public function __construct(array $config)
{
$this->config = $config;
// logic to connect to MongoDB
}
public function create(string $identity, array $data = []): void
{
// logic to create a new session record
}
public function load(string $token, ?array &$sessionData = null): bool
{
// logic to load session data by token
return true;
}
public function getToken(): ?string
{
// return current token
return 'token';
}
public function getIdentity(): ?string
{
// return current identity
return 'user_id';
}
public function isEmpty(): bool
{
// check if session is empty
return false;
}
public function has(string $key): bool
{
// check if key exists in session data
return isset($this->data[$key]);
}
public function get(string $key): mixed
{
// get value from session data
return $this->data[$key] ?? null;
}
public function set(string $key, mixed $value): void
{
// set value in session data
}
public function unset(string $key): void
{
// remove value from session data
}
public function clear(): void
{
// clear all session data
}
public function read(): array
{
// return all session data
return [];
}
}Then, configure your application to use this new class:
// app/configs/app.php
'auth' => [
'backend' => \App\Auth\Backend\MongoDBSession::class,
'mongodbsession' => [ // Configuration for your class
'collection' => 'user_sessions',
],
],Custom Session Transport
To create a custom transport (e.g., to read the token from the query string or a custom encoded payload), create a class that implements the Hazaar\Auth\Interface\SessionTransport interface.
<?php
namespace App\Auth\Transport;
use Hazaar\Auth\Interface\SessionTransport;
use Hazaar\Controller\Response;
class QueryString implements SessionTransport
{
private array $config;
public function __construct(array $config)
{
$this->config = $config;
}
public function extractToken(): ?string
{
// logic to extract token from request
return $_GET['token'] ?? null;
}
public function persistToken(Response $response, string $token, array $options = []): void
{
// logic to add token to response (usually not needed for QueryString transport as it's inbound only,
// but maybe you redirect with it)
}
public function clearToken(Response $response, array $options = []): void
{
// logic to clear token (client side action usually)
}
}Then, configure it in app.php:
// app/configs/app.php
'auth' => [
'transport' => \App\Auth\Transport\QueryString::class,
],Summary
The Hazaar Authentication system provides a robust and flexible foundation for securing your application.
- Decoupled Architecture: By separating the identity check (Adapter), storage (Backend), and delivery (Transport), you can mix and match components to suit any architecture, from simple monoliths to complex microservices.
- Flexible Adapters: The
Adapteris where the "real work" happens. Because you implement thequeryAuthmethod yourself, you are not tied to a specific database table or structure. You can authenticate users against:- Relational Databases (MySQL, PostgreSQL)
- NoSQL Databases
- LDAP / Active Directory
- External REST APIs / OAuth Providers
- Static configuration files
- Extensible: With the ability to implement custom interfaces, the system can grow with your application's requirements.
By leveraging these components, you can ensure your application is secure while maintaining the flexibility to adapt to future infrastructure changes.