Pramnos Authentication & User Management Guide¶
Overview¶
The Pramnos Framework provides a comprehensive authentication system that supports multiple authentication methods, user management, permissions, JWT tokens, session management, and OAuth2 capabilities. The system is modular and extensible through addons.
v1.2 New Features: - Database Authentication Driver — Native auth without addons - Two-Factor Authentication (2FA/TOTP) — Time-based one-time passwords - Login Lockout — Brute-force protection with exponential backoff - Session Tracking — Bot detection and session monitoring - OAuth2 Server — Full
league/oauth2-serverintegration - Security Hardening — CSRF, session cookie, view escaping - Auto-Login Lifecycle — Built-in login/logout handlingSee related guides: Pramnos_Security_Guide.md, Pramnos_Authorization_Guide.md
Architecture¶
Core Components¶
- Auth System (
Pramnos\Auth\Auth) - Main authentication controller - User Management (
Pramnos\User\User) - User data and operations - JWT Support (
Pramnos\Auth\JWT) - JSON Web Token implementation - Permissions (
Pramnos\Auth\Permissions) - Access control system - Session Management (
Pramnos\Http\Session) - Session handling - Token Management (
Pramnos\User\Token) - User tokens and API access
Authentication Flow¶
// Basic authentication flow
$auth = \Pramnos\Auth\Auth::getInstance();
$success = $auth->auth($username, $password, $rememberMe);
if ($success) {
// User is authenticated, session is set
$user = \Pramnos\User\User::getCurrentUser();
} else {
// Authentication failed
$response = $auth->lastResponse;
echo $response['message'];
}
User Authentication¶
Basic Login¶
// Simple login
$auth = \Pramnos\Auth\Auth::getInstance();
$result = $auth->auth('user@example.com', 'password');
if ($result) {
echo "Login successful";
// User session is automatically created
} else {
echo "Login failed: " . $auth->lastResponse['message'];
}
Login with Remember Me¶
// Login with persistent session
$auth = \Pramnos\Auth\Auth::getInstance();
$result = $auth->auth('user@example.com', 'password', true); // Third parameter enables "remember me"
if ($result) {
// User will stay logged in across browser sessions
$user = \Pramnos\User\User::getCurrentUser();
}
Encrypted Password Authentication¶
// Login with pre-encrypted password (for API scenarios)
$auth = \Pramnos\Auth\Auth::getInstance();
$hashedPassword = password_hash('plaintext_password', PASSWORD_DEFAULT);
$result = $auth->auth('user@example.com', $hashedPassword, false, true); // Fourth parameter indicates encrypted password
Logout¶
// Logout current user
$auth = \Pramnos\Auth\Auth::getInstance();
$auth->logout();
// This triggers the 'Logout' addon events and clears the session
Credential Verification (Without Session)¶
If you need to verify a user's credentials (username/password) without actually logging them in (e.g. for API tokens, OAuth2 Password Grants, or verifying a password before sensitive actions), use the central static method User::validateUserCredentials():
$credentials = \Pramnos\User\User::validateUserCredentials($username, $password);
if ($credentials !== false) {
// Credentials match!
$userId = $credentials['userid'];
$username = $credentials['username'];
$email = $credentials['email'];
} else {
// Invalid credentials
}
This method delegates to Auth::getInstance()->verifyCredentials($username, $password) which resolves the active authentication logic in the proper priority order (respecting any registered addons like UserDatabase or custom AuthDriverInterface drivers).
User Management¶
Creating Users¶
// Create a new user
$user = new \Pramnos\User\User();
$user->username = 'johndoe';
$user->email = 'john@example.com';
$user->password = password_hash('password', PASSWORD_DEFAULT);
$user->firstname = 'John';
$user->lastname = 'Doe';
$user->status = 1; // Active
$user->save();
Loading Users¶
// Load user by ID
$user = new \Pramnos\User\User(123);
// Load user by username/email
$user = new \Pramnos\User\User();
$user->loadByUsername('johndoe');
// Get current logged-in user
$currentUser = \Pramnos\User\User::getCurrentUser();
if ($currentUser) {
echo "Welcome, " . $currentUser->firstname;
}
User Data Management¶
$user = new \Pramnos\User\User(123);
// Get user data as array
$userData = $user->getData();
// Update user information
$user->email = 'newemail@example.com';
$user->save();
// Delete user
$user->delete();
JWT Token Authentication¶
Generating JWT Tokens¶
// Create JWT token for user
$payload = [
'userId' => $user->userid,
'username' => $user->username,
'exp' => time() + 3600, // Expires in 1 hour
'iat' => time(), // Issued at
];
$secret = 'your-secret-key';
$token = \Pramnos\Auth\JWT::encode($payload, $secret, 'HS256');
Validating JWT Tokens¶
try {
$secret = 'your-secret-key';
\Pramnos\Auth\JWT::$leeway = 60; // Allow 60 seconds clock skew
$decoded = \Pramnos\Auth\JWT::decode($token, $secret, ['HS256']);
// Token is valid, load user
$user = new \Pramnos\User\User($decoded->userId);
} catch (\Exception $e) {
// Token validation failed
echo "Invalid token: " . $e->getMessage();
}
API Authentication with JWT¶
// In API controllers, JWT is automatically handled
class ApiController extends \Pramnos\Application\Controller
{
public function secureEndpoint()
{
// JWT token is validated automatically if present in HTTP_ACCESSTOKEN header
if (!isset($_SESSION['user']) || !is_object($_SESSION['user'])) {
return ['status' => 401, 'message' => 'Authentication required'];
}
$user = $_SESSION['user'];
return ['status' => 200, 'data' => 'Protected data for user ' . $user->userid];
}
}
Token Management¶
User Tokens¶
The framework supports various token types for different purposes:
$user = new \Pramnos\User\User(123);
// Add authentication token
$token = $user->addToken('auth', bin2hex(random_bytes(32)), 'API access token');
// Add Apple Push Notification token
$apnsToken = $user->addToken('apns', $deviceToken, 'iPhone device');
// Add OAuth2 access token
$accessToken = $user->addToken('access_token', $oauthToken, 'OAuth2 access', $refreshTokenId);
Token Operations¶
$user = new \Pramnos\User\User(123);
// Get user's active auth token
$authToken = $user->getToken();
// Get all user tokens
$allTokens = $user->getAllTokens();
// Load user by token
$user->loadByToken($tokenString, 'auth');
// Clean up old tokens (older than 30 days)
\Pramnos\User\User::cleanupAllAuthTokens(30);
Working with Token Objects¶
// Create token object
$token = new \Pramnos\User\Token();
$token->userid = $user->userid;
$token->tokentype = 'auth';
$token->token = bin2hex(random_bytes(32));
$token->notes = 'Mobile app access';
$token->expires = time() + (30 * 24 * 60 * 60); // 30 days
$token->save();
// Load existing token
$existingToken = new \Pramnos\User\Token($tokenId);
$details = $existingToken->getDetails();
// Track token usage
$existingToken->addAction(); // Logs the current request
Permissions System¶
Setting Permissions¶
// Grant permission to user
\Pramnos\Auth\Permissions::allow(
$userId, // Subject (user ID)
'articles', // Resource
'create', // Privilege
0, // Resource element (0 for all)
'module', // Resource type
'user' // Subject type
);
// Grant permission to group
\Pramnos\Auth\Permissions::allow(
'editors', // Subject (group name)
'articles', // Resource
'edit', // Privilege
0, // Resource element
'module', // Resource type
'group' // Subject type
);
// Deny permission
\Pramnos\Auth\Permissions::deny(
$userId,
'admin',
'access',
0,
'module',
'user'
);
Checking Permissions¶
// Check if user has permission
$hasPermission = \Pramnos\Auth\Permissions::check(
$userId, // Subject
'articles', // Resource
'create', // Privilege
0, // Resource element
'module', // Resource type
'user' // Subject type
);
if ($hasPermission) {
// User can create articles
$this->showCreateForm();
} else {
// Access denied
throw new \Exception('Insufficient permissions', 403);
}
Group-Based Permissions¶
// Users inherit permissions from their groups
$user = new \Pramnos\User\User($userId);
$userGroups = $user->getUserGroups(); // Get user's groups
// Check permission considering group membership
$hasPermission = \Pramnos\Auth\Permissions::check(
$userId,
'articles',
'publish',
0,
'module',
'user'
); // Automatically checks group permissions too
Session Management¶
Basic Session Operations¶
$session = \Pramnos\Http\Session::getInstance();
// Check if user is logged in
if ($session->isLogged()) {
$userId = $_SESSION['uid'];
$username = $_SESSION['username'];
}
// Create snapshot for post-login redirect
$session->snapshot($_SERVER['REQUEST_URI']);
// Get and clear snapshot
$returnUrl = $session->getSnapshot();
if ($returnUrl) {
$this->redirect($returnUrl);
}
Session Security¶
$session = \Pramnos\Http\Session::getInstance();
// Get session token for CSRF protection
$token = $session->getToken();
// Validate CSRF token
if ($session->checkToken('post', 'csrf_')) {
// Token is valid, process request
} else {
// Invalid token, possible CSRF attack
throw new \Exception('Invalid security token', 403);
}
// Reset session (for logout)
$session->reset();
Authentication Addons¶
User Database Addon¶
The framework includes a user database addon for standard username/password authentication:
// The UserDatabase addon is automatically triggered during authentication
// It checks credentials against the users table
// Custom validation can be added by extending the addon
class CustomUserAuth extends \Pramnos\Addon\Auth\UserDatabase
{
public function onAuth($username, $password, $remember, $encryptedPassword, $validate)
{
// Add custom validation logic
$result = parent::onAuth($username, $password, $remember, $encryptedPassword, $validate);
if ($result['status']) {
// Additional checks (e.g., account verification, 2FA)
if (!$this->isTwoFactorVerified($result['uid'])) {
return [
'status' => false,
'message' => 'Two-factor authentication required',
'statusCode' => 401
];
}
}
return $result;
}
}
Creating Custom Authentication Addons¶
class LdapAuth extends \Pramnos\Addon\Addon
{
public function onAuth($username, $password, $remember, $encryptedPassword, $validate)
{
// LDAP authentication logic
$ldapConnection = ldap_connect($this->config['ldap_server']);
if (ldap_bind($ldapConnection, $username, $password)) {
// Authentication successful
$userInfo = $this->getLdapUserInfo($ldapConnection, $username);
return [
'status' => true,
'username' => $username,
'uid' => $userInfo['uid'],
'email' => $userInfo['email'],
'auth' => password_hash($password, PASSWORD_DEFAULT)
];
}
return [
'status' => false,
'message' => 'LDAP authentication failed'
];
}
}
Controller Authentication¶
Protecting Controller Actions¶
class ArticleController extends \Pramnos\Application\Controller
{
public function __construct(?\Pramnos\Application\Application $application = null)
{
// Define public actions (no authentication required)
$this->addAction(['display', 'view']);
// Define authenticated actions (login required)
$this->addAuthAction(['create', 'edit', 'delete', 'save']);
parent::__construct($application);
}
public function display()
{
// Public action - anyone can access
return $this->getView('article')->display();
}
public function create()
{
// Authenticated action - user must be logged in
// Framework automatically checks authentication
return $this->getView('article')->display('create');
}
}
API Authentication¶
class ApiController extends \Pramnos\Application\Controller
{
public function __construct(?\Pramnos\Application\Application $application = null)
{
// API endpoints typically require authentication
$this->addAuthAction(['list', 'create', 'update', 'delete']);
parent::__construct($application);
}
public function list()
{
// Check if user is authenticated via JWT or session
if (!isset($_SESSION['user']) || !is_object($_SESSION['user'])) {
return ['status' => 401, 'error' => 'Authentication required'];
}
$user = $_SESSION['user'];
// Return data specific to the authenticated user
return ['status' => 200, 'data' => $this->getUserData($user->userid)];
}
}
Advanced Features¶
Login Lockout (Brute-Force Protection)¶
Pramnos\Auth\Loginlockout — progressive brute-force lockout for login endpoints.
Tracks failed login attempts per scope+identifier pair. Three scopes are supported: 'user' (by user ID), 'identifier' (by normalized email/username), and 'ip' (by remote address).
Default thresholds¶
| Failures | Lockout duration |
|---|---|
| 3 | 60 s (1 minute) |
| 5 | 300 s (5 minutes) |
| 7 | 900 s (15 minutes) |
| 10+ | 3600 s (1 hour) |
A sliding window of 900 seconds applies: if the gap between the previous failure and the current attempt exceeds the window, the counter resets to 1. This prevents indefinite accumulation from past brute-force campaigns.
Usage¶
use Pramnos\Auth\Loginlockout;
$lockout = new Loginlockout();
// Check BEFORE processing the login attempt
$status = $lockout->getLockoutStatus('identifier', strtolower($email));
// Returns: ['locked' => bool, 'remaining' => int]
if ($status['locked']) {
return ['status' => 429, 'retry_after' => $status['remaining']];
}
// Attempt authentication ...
if ($authFailed) {
// Record failure for all applicable scopes
$lockout->recordFailedAttempt('identifier', strtolower($email));
$lockout->recordFailedAttempt('user', (string) $userId);
$lockout->recordFailedAttempt('ip', $ipAddress);
} else {
// Clear state on success
$lockout->clearSuccessfulLoginState('identifier', strtolower($email));
$lockout->clearSuccessfulLoginState('user', (string) $userId);
$lockout->clearSuccessfulLoginState('ip', $ipAddress);
}
API¶
| Method | Description |
|---|---|
recordFailedAttempt(string $scope, string $identifier): void |
Increment failure counter; apply threshold; creates row if absent |
getLockoutStatus(string $scope, string $identifier): array |
Returns ['locked' => bool, 'remaining' => int]; 0 remaining when not locked |
clearSuccessfulLoginState(string $scope, string $identifier): void |
Deletes the tracking row — fully resets counter and lockout |
Constants¶
| Constant | Value |
|---|---|
Loginlockout::DEFAULT_WINDOW_SECONDS |
900 |
Loginlockout::DEFAULT_STEPS |
[3=>60, 5=>300, 7=>900, 10=>3600] |
Two-Factor Authentication (TOTP)¶
Two classes: TOTPHelper (pure static, no DB) and TwoFactorAuthService (stateful, DB-backed).
Compatible with Google Authenticator, Authy, and any RFC 6238 TOTP app.
TOTPHelper — setup and verification¶
use Pramnos\Auth\TOTPHelper;
// Generate a new shared secret (once per user, during setup)
$secret = TOTPHelper::generateSecret(); // e.g., 'JBSWY3DPEHPK3PXP'
// Verify a user-submitted code (±1 window drift tolerance)
$valid = TOTPHelper::verifyCode($secret, $userCode); // bool
// QR code as an inline data URI — no external API calls, CSP-safe
$dataUri = TOTPHelper::getQRCodeDataUri($secret, 'user@example.com', 'MyApp');
// Returns 'data:image/svg+xml;base64,…' (requires chillerlan/php-qrcode ^5.0) or null
// Build the provisioning URI
$uri = TOTPHelper::buildOtpAuthUri($secret, 'user@example.com', 'MyApp');
// 'otpauth://totp/MyApp:user%40example.com?secret=…&issuer=MyApp'
// Backup codes
$codes = TOTPHelper::generateBackupCodes(10); // ['ABCD2345', ...]
$hash = TOTPHelper::hashBackupCode($codes[0]); // bcrypt hash for storage
$isMatch = TOTPHelper::verifyBackupCode($code, $hash); // bool, case-insensitive
// Utilities
$remaining = TOTPHelper::getRemainingTime(); // seconds until window expires [1, 30]
$isValid = TOTPHelper::isValidSecret($secret); // validate base32 format
Security note:
getQRCodeUrl()sends the TOTP secret to an external API and is deprecated. Always usegetQRCodeDataUri()instead.
TwoFactorAuthService — full setup flow¶
use Pramnos\Auth\TwoFactorAuthService;
$svc = new TwoFactorAuthService(); // uses Factory::getDatabase()
// Step 1 — generate secret and show QR code to user
$info = $svc->startSetup($userId, $userEmail);
// ['secret', 'qr_code_data_uri', 'qr_code_url', 'manual_entry_key', 'backup_codes']
// Show backup_codes ONCE — user must record them
// Step 2 — user scans QR, enters first code to confirm
$success = $svc->completeSetup($userId, $submittedCode); // bool
// Verify on login
$valid = $svc->verifyCode($userId, $code); // accepts TOTP or backup code
// State queries
$enabled = $svc->isEnabled($userId); // bool
$remaining = $svc->getRemainingBackupCodes($userId); // int
$status = $svc->getStatus($userId);
// ['enabled' => bool, 'setup' => bool, 'backup_codes_remaining' => int]
// Management
$svc->disable($userId); // clears secret, sets enabled=0
$newCodes = $svc->regenerateBackupCodes($userId); // string[]|false
$svc->cleanupExpiredSessions(); // removes used/expired setup rows
Replay protection: verifyCode() compares the current 30-second window against last_used. If the same window was already used, the code is rejected even if cryptographically valid.
Backup codes are one-time: the matching hash is removed from storage after successful verification.
Database tables¶
| Table | Description |
|---|---|
user_twofactor |
One row per user — enabled flag, secret, backup code hashes, last_used |
twofactor_setup |
Temporary setup sessions (15-min TTL) |
twofactor_attempts |
Append-only attempt log (TimescaleDB hypertable where available) |
Password Security¶
class SecureUser extends \Pramnos\User\User
{
public function setPassword($plainPassword)
{
// Validate password strength
if (!$this->isPasswordStrong($plainPassword)) {
throw new \Exception('Password does not meet security requirements');
}
// Hash with current best practices
$this->password = password_hash($plainPassword, PASSWORD_ARGON2ID, [
'memory_cost' => 65536,
'time_cost' => 4,
'threads' => 3
]);
}
public function verifyPassword($plainPassword)
{
return password_verify($plainPassword, $this->password);
}
private function isPasswordStrong($password)
{
// Implement password strength requirements
return strlen($password) >= 8
&& preg_match('/[A-Z]/', $password)
&& preg_match('/[a-z]/', $password)
&& preg_match('/[0-9]/', $password)
&& preg_match('/[^A-Za-z0-9]/', $password);
}
}
OAuth2 Scopes and Policy¶
Pramnos\Auth\Scopes — static scope registry for OAuth2 consent screens and validation.
use Pramnos\Auth\Scopes;
// All scopes grouped by category (consent screen)
$grouped = Scopes::getScopes();
// ['Personal User Data' => ['profile' => [...], 'email' => [...]], ...]
// Flat scope → description map
$descriptions = Scopes::getScopeDescriptions();
// Scopes implicitly granted to all clients
$defaults = Scopes::getDefaultScopes(); // ['profile', 'email', 'user']
// Validate a scope string
[$hasInvalid, $invalidList] = Scopes::hasInvalidScopes('profile email unknown_scope');
// Resolve inherited scopes transitively
$resolved = Scopes::resolveInheritedScopes('system:notifications_write');
// ['system:notifications_read', 'system:notifications_write']
Standard scopes: profile, email, phone, address, user, openid, offline_access, system:admin, system:audit_read, system:health, system:notifications_read/write.
Pramnos\Auth\OAuthPolicyHelper — server-wide OAuth2 policy defaults.
use Pramnos\Auth\OAuthPolicyHelper;
$methods = OAuthPolicyHelper::getDefaultAllowedAuthMethods();
// ['client_secret_basic', 'client_secret_post', 'private_key_jwt']
$grants = OAuthPolicyHelper::getDefaultAllowedGrantTypes();
// ['authorization_code', 'client_credentials', 'device_code', 'refresh_token', 'exchange_token']
// 'password' grant excluded (deprecated per RFC 9126 / OAuth 2.1)
OAuth2 Integration¶
// OAuth2 server capabilities are built into the API system
class OAuth2Controller extends \Pramnos\Application\Controller
{
public function authorize()
{
// Handle OAuth2 authorization requests
$clientId = $_GET['client_id'];
$redirectUri = $_GET['redirect_uri'];
$scope = $_GET['scope'] ?? 'read';
// Validate client application
$app = new \Pramnos\Application\Api\Apikey($clientId);
if ($app->appid == 0 || $app->callback !== $redirectUri) {
throw new \Exception('Invalid client application');
}
// If user is not logged in, redirect to login
if (!\Pramnos\Http\Session::staticIsLogged()) {
$this->redirect('/login?return_to=' . urlencode($_SERVER['REQUEST_URI']));
return;
}
// Generate authorization code
$user = \Pramnos\User\User::getCurrentUser();
$authCode = bin2hex(random_bytes(32));
$user->addToken('auth_code', $authCode, 'OAuth2 authorization code', null);
// Redirect back to client with code
$this->redirect($redirectUri . '?code=' . $authCode . '&state=' . ($_GET['state'] ?? ''));
}
}
Configuration¶
Authentication Settings¶
// In your application configuration
return [
'authentication' => [
'jwt_secret' => env('JWT_SECRET', 'your-secret-key'),
'jwt_expiry' => env('JWT_EXPIRY', 3600), // 1 hour
'session_timeout' => env('SESSION_TIMEOUT', 1800), // 30 minutes
'remember_me_duration' => env('REMEMBER_ME_DURATION', 2592000), // 30 days
'password_hash_algo' => PASSWORD_ARGON2ID,
'require_email_verification' => env('REQUIRE_EMAIL_VERIFICATION', true),
'enable_mfa' => env('ENABLE_MFA', false),
],
'permissions' => [
'cache_permissions' => env('CACHE_PERMISSIONS', true),
'default_user_permissions' => [
'profile' => ['read', 'update'],
'content' => ['read']
]
]
];
Database Setup¶
The authentication system requires several database tables. Use the framework's migration system to set them up:
-- Users table
CREATE TABLE `users` (
`userid` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`firstname` varchar(255),
`lastname` varchar(255),
`status` tinyint DEFAULT 1,
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`userid`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`)
);
-- User tokens table
CREATE TABLE `usertokens` (
`tokenid` int NOT NULL AUTO_INCREMENT,
`userid` int NOT NULL,
`tokentype` varchar(50) NOT NULL,
`token` varchar(255) NOT NULL,
`created` int NOT NULL,
`lastused` int DEFAULT 0,
`expires` int DEFAULT NULL,
`status` tinyint DEFAULT 1,
`notes` text,
PRIMARY KEY (`tokenid`),
KEY `userid` (`userid`),
KEY `token` (`token`),
FOREIGN KEY (`userid`) REFERENCES `users` (`userid`) ON DELETE CASCADE
);
-- Permissions table
CREATE TABLE `permissions` (
`id` int NOT NULL AUTO_INCREMENT,
`subject` varchar(255) NOT NULL,
`subjecttype` enum('user','group') NOT NULL,
`resource` varchar(255) NOT NULL,
`resourcetype` varchar(255) NOT NULL,
`privilege` varchar(255) NOT NULL,
`resourceelement` varchar(255) DEFAULT '0',
`value` tinyint NOT NULL DEFAULT 1,
PRIMARY KEY (`id`),
KEY `subject_resource` (`subject`, `resource`, `privilege`)
);
Best Practices¶
Security Guidelines¶
- Always use prepared statements - The framework's
prepareQuery()method prevents SQL injection - Validate JWT tokens properly - Set appropriate expiry times and validate all claims
- Use strong passwords - Implement password complexity requirements
- Enable CSRF protection - Use session tokens for form submissions
- Implement rate limiting - Prevent brute force attacks on login endpoints
- Use HTTPS - Always transmit authentication data over secure connections
- Log security events - Monitor failed login attempts and permission violations
Performance Considerations¶
- Cache permissions - Use the caching system for frequently checked permissions
- Optimize token queries - Index token tables properly
- Clean up expired tokens - Regularly remove old authentication tokens
- Use efficient session storage - Consider Redis for session storage in production
Error Handling¶
try {
$auth = \Pramnos\Auth\Auth::getInstance();
$result = $auth->auth($username, $password);
if (!$result) {
$response = $auth->lastResponse;
\Pramnos\Logs\Logger::logWarning('Failed login attempt', [
'username' => $username,
'ip' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'reason' => $response['message']
]);
return ['status' => 401, 'message' => 'Authentication failed'];
}
} catch (\Exception $e) {
\Pramnos\Logs\Logger::logError('Authentication error', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return ['status' => 500, 'message' => 'Internal authentication error'];
}
This authentication system provides a robust foundation for securing your Pramnos Framework applications with support for modern authentication patterns, comprehensive user management, and flexible permission systems.
Related Documentation¶
- Framework Guide - Core framework concepts and MVC patterns
- Database API Guide - Database operations for user data management
- Cache System Guide - Caching user sessions and permissions
- Console Commands Guide - CLI tools for user management
- Logging System Guide - Logging authentication events and security monitoring
- Email System Guide - Password reset and notification emails
- Internationalization Guide - Multi-language authentication flows
For additional information on implementing authentication in your controllers and APIs, see the Framework Guide section on authentication patterns.