← All documentation
Topics

- Working with data
- Designer components
- Field controls
- Search & filtering
- Calendars
- PDF & printing
- Email
- SMS
- Notifications
- Security
- Helper functions
- JavaScript API
- Performance

# Security API – `Security` Class

The Security class provides a complete authentication, authorisation and protection toolkit. It covers user login/logout, session management, permissions, owner‑based row‑level security, password hashing, CSRF, rate limiting, TOTP two‑factor authentication and secure "Remember Me" cookies. Every method is static and safe – no manual session manipulation needed.

## Contents

- Authentication – Login, Logout, LoginAs
- User State – IsLoggedIn, IsAdmin, CurrentUser*, etc.
- Auth Guards – RequireAuth, RequireRole
- Table‑level Permissions
- Allowed Pages
- OwnerID (Row‑level Security)
- Password Utilities
- Remember Me
- CSRF Protection
- Rate Limiting
- Two‑factor Authentication (TOTP)
- Display Name
- Secure Token Generation

## Authentication

### Login – Standard username/password

    // Basic login
    if (Security::Login($username, $password)) {
        echo "Welcome, " . Security::CurrentUsername();
    } else {
        echo "Invalid credentials.";
    }

### Login with “Remember Me”

    // Pass true to set a persistent cookie (30 days)
    Security::Login($username, $password, true);

### Login without password (e.g. after OAuth)

    // LoginAs only needs a username – no password check
    Security::LoginAs('john.doe');

### Check credentials without logging in

    if (Security::CheckUsernamePassword('admin', 'secret')) {
        // valid, but session is unchanged
    }

### Logout

    Security::Logout();
    // After logout, all session data is removed.
    // You should redirect to the login page.
    header('Location: /login');

## User State

    // Is anybody logged in?
    if (Security::IsLoggedIn()) { … }

    // Is the current user a superadmin?
    if (Security::IsAdmin()) { … }

    // Is the visitor a guest?
    if (Security::IsGuest()) { … }

    // Get the username
    echo Security::CurrentUsername();   // e.g. "john.doe"

    // Get the role/group
    echo Security::CurrentUserGroup();  // "superadmin", "developer", "user"

    // Get all groups (array) – currently wraps role in an array
    $groups = Security::CurrentUserGroups();

    // Full user data array (cached in session)
    $user = Security::CurrentUserData();
    echo $user['email'];

    // Reload user data from database
    Security::RefreshUserData();

## Table‑level Permissions

Each table has seven permission bits: Add, Delete, Edit, Search/List, Print/Export, Import, Manage (admin).

### Set permissions for a table

    // Using a string (each letter grants the corresponding right)
    Security::SetPermissions('orders', 'ADES');   // can add, delete, edit, search

    // Using an array
    Security::SetPermissions('products', [
        'A' => true,
        'D' => false,
        'E' => true,
        'S' => true,
        'P' => true,
        'I' => false,
        'M' => false
    ]);

### Check a specific permission

    if (Security::HasPermission('orders', 'E')) {
        echo "User can edit orders.";
    } else {
        echo "Edit access denied.";
    }

### Retrieve all permissions for a table

    $perms = Security::GetPermissions('orders');
    if ($perms['A']) { echo "Can add"; }

## Allowed Pages

Fine‑grained control over which individual pages a user can access for a table and page type (list, add, edit, view, print, search).

### Set allowed pages

    // Allow only the "summary" and "details" pages for the list type
    Security::SetAllowedPages('orders', 'list', ['summary', 'details']);

    // A single page as a string
    Security::SetAllowedPages('orders', 'add', 'order_add');

### Get allowed pages

    $pages = Security::GetAllowedPages('orders', 'list');
    if (in_array('summary', $pages)) {
        echo "Summary page is allowed.";
    }

## OwnerID (Row‑level Security)

When a table has “own data only” security, the system needs to know which ID belongs to the current user. OwnerID stores that value.

### Set OwnerID

    // After login, set the user's ID as the owner for the customers table
    Security::SetOwnerId('customers', $user['id']);

### Get OwnerID

    $ownerId = Security::GetOwnerId('customers');
    DB::Select('customers', ['assigned_to' => $ownerId]);

## Password Utilities

### Hash a password

    $hashed = Security::HashPassword('mySecureP@ss');
    // Uses bcrypt (PASSWORD_DEFAULT)

### Verify a password

    if (Security::VerifyPassword('mySecureP@ss', $hashed)) {
        // valid
    }

### Check if a hash needs rehashing

    if (Security::PasswordNeedsRehash($hashed)) {
        $newHash = Security::HashPassword($newPassword);
        DB::Update('users', ['password' => $newHash], ['id' => $userId]);
    }

## Remember Me

    // When logging in with rememberMe = true, a long‑lived cookie is set.
    Security::Login($username, $password, true);

    // On subsequent visits, before any authentication check:
    if (!Security::IsLoggedIn() && Security::LoginFromRememberMe()) {
        // User was logged in via cookie; session is now active.
    }

Security note: The “Remember Me” feature stores a hashed token in the database. The plain token is never stored on the server.

## CSRF Protection

    // Generate a CSRF token (stored in session)
    $token = Security::CSRF()->Token();

    // Output a hidden field in a form
    echo Security::CSRF()->HiddenField();

    // Check a submitted token
    if (!Security::CSRF()->Check($_POST['_token'] ?? '')) {
        die('Invalid CSRF token.');
    }

    // Regenerate token (e.g. after login)
    Security::CSRF()->Regenerate();

Important: Always include the CSRF token in POST forms. The `Check()` method uses `hash_equals()` for timing‑safe comparison.

## Rate Limiting

    // Protect a login endpoint from brute‑force attacks
    $key = 'login:' . $_SERVER['REMOTE_ADDR'];
    $maxAttempts = 5;
    $window = 60; // 60 seconds

    if (!Security::RateLimit()->Check($key, $maxAttempts, $window)) {
        $remaining = Security::RateLimit()->Remaining($key, $maxAttempts, $window);
        die("Too many attempts. Try again in $window seconds.");
    }

    // After a failed login:
    Security::RateLimit()->Hit($key);

    // After a successful login, you can clear the rate limit:
    // (Manually unset the session key or wait for the window to expire)

## Two‑factor Authentication (TOTP)

    // Generate a secret for a user
    $secret = Security::TOTP()->GenerateSecret();   // e.g. "JBSWY3DPEHPK3PXP"
    DB::Update('users', ['totp_secret' => $secret], ['id' => $userId]);

    // Get the QR code URL (for apps like Google Authenticator)
    $qrUrl = Security::TOTP()->GetQRCodeUrl($username, $secret, 'MyApp');
    // Display as a QR image using a service or JavaScript library

    // Verify a code entered by the user
    $code = $_POST['totp_code'];   // 6 digits
    if (Security::TOTP()->Verify($secret, $code)) {
        echo "Code is valid!";
    } else {
        echo "Invalid code.";
    }

    // Verify with a wider time drift (±2 periods, ±60 seconds)
    Security::TOTP()->Verify($secret, $code, 2);

## Display Name

    // Get the current user's display name
    echo Security::GetDisplayName();   // returns fullname, or username as fallback

    // Set a custom display name in the session (temporary)
    Security::SetDisplayName('John (Admin)');

## Secure Token Generation

    // Generate a cryptographically secure random token (hex)
    $token = Security::GenerateToken();           // 64 hex chars (32 bytes)
    $shortToken = Security::GenerateToken(16);    // 32 hex chars (16 bytes)
    // Use for CSRF, password resets, invitation links, etc.

## Auth Guards – RequireAuth, RequireRole

These are shortcut methods that immediately stop the request if the user is not authenticated or lacks the required role. They replace the repetitive guard code that was previously duplicated in every controller.

### RequireAuth()

Redirects to the login page if the user is not logged in. Use it at the top of any protected method.

    // Protect a whole controller method
    public function listProjects(): void {
        Security::RequireAuth();
        // ... your code here
    }

### RequireRole(array $roles)

Stops with a 403 Forbidden message if the current user's role is not in the allowed list.

    // Only superadmin and developer can create projects
    Security::RequireRole(['superadmin', 'developer']);

### Combined example

    public function createProject(): void {
        Security::RequireAuth();
        Security::RequireRole(['superadmin', 'developer']);
        // proceed with project creation...
    }

### 🔗 Related Help Topics

Database API Email API SMS API