The Trongate Security Module
The Trongate_security module provides a centralized way to handle authorization across your application using scenarios.
Instead of scattering security checks throughout your codebase, you call one method and let it route to the appropriate handler:
$this->trongate_security->make_sure_allowed('scenario_name');This approach keeps your security logic organized, consistent, and easy to maintain.
What Are Scenarios?
A scenario is a named security context that describes what access control rules should apply.
Examples of scenarios:
'admin panel'- Only administrators can access'members area'- Any logged-in member can access'read comment'- Anyone can access (public)'edit comment'- Only comment owner or admin can access'premium content'- Only premium subscribers can access
Each scenario routes to a specific module that knows how to handle that particular type of access control.
It is for you - the developer - to decide how many scenarios your application is going to have. You also, as the developer, determine what names each scenario should be given.
How It Works
The Trongate_security module uses a switch statement to delegate scenarios to appropriate modules. The default scenario handles admin panel access by checking for a valid token with user level 1:
<?php
class Trongate_security extends Trongate {
public function __construct(?string $module_name = null) {
parent::__construct($module_name);
block_url($this->module_name);
}
public function make_sure_allowed(string $scenario = 'admin panel', array $params = []): mixed {
switch ($scenario) {
// case 'members area':
// $result = $this->members->make_sure_allowed($scenario, $params);
// return $result;
default:
// Default: admin panel access
// Checks for a valid token for user level 1 (administrators)
$token = $this->trongate_tokens->attempt_get_valid_token(1);
if ($token === false) {
if (ENV === 'dev') {
// Dev mode convenience: create a token and redirect to login
redirect('login/login');
} else {
redirect('login/login');
}
}
return $token;
}
}
}The commented-out case shows how to add custom scenarios. Uncomment and modify as needed for your application.
In development mode (ENV === 'dev'), the login module provides convenience features to streamline development. In production, unauthenticated users are always redirected to the login page at login/login.
The Default Scenario
If you do not specify a scenario, it defaults to 'admin panel':
// These two calls are identical
$this->trongate_security->make_sure_allowed();
$this->trongate_security->make_sure_allowed('admin panel');Both check for a valid token with user level 1 (administrators) and redirect to login/login if none is found.
Return Values: Flexible by Design
The method is intentionally open-ended. It can return:
- String - The validated token
- Boolean -
truefor public access,falsefor denied - Object - Complete user object with permissions
- Array - Custom data structure with multiple values
- Nothing - Can redirect or die instead of returning
The return type depends on what your scenario needs. You decide.
This flexibility means make_sure_allowed() can adapt to any authorization pattern your application requires.
Example: Discussion Forum
Let us build a hypothetical discussion forum accessible by the public, with special privileges for admin users and member users.
The Requirements
- Read comments - Open to anyone (no authentication)
- Create comments - Must be a logged-in member
- Edit/delete comments - Must be the comment owner OR an admin
Trongate_security.php
Add forum scenarios to the switch statement:
public function make_sure_allowed(string $scenario = 'admin panel', array $params = []): mixed {
switch ($scenario) {
case 'read comment':
// Public access - no authentication required
return true;
case 'create comment':
// Must be a member (user level 2)
$token = $this->trongate_tokens->attempt_get_valid_token(2);
if ($token === false) {
redirect('login/login');
}
return $token;
case 'edit comment':
case 'delete comment':
// Delegate to members module for ownership check
$result = $this->members->make_sure_allowed($scenario, $params);
return $result;
default:
// Admin panel access - checks for user level 1 token
$token = $this->trongate_tokens->attempt_get_valid_token(1);
if ($token === false) {
redirect('login/login');
}
return $token;
}
}Members.php
The members module handles complex ownership checks:
public function make_sure_allowed(string $scenario = 'members area', array $params = []): mixed {
block_url('members/make_sure_allowed');
switch ($scenario) {
case 'edit comment':
case 'delete comment':
$comment_id = $params['comment_id'] ?? null;
if (!is_numeric($comment_id)) {
http_response_code(400);
die('Invalid comment ID');
}
// Get current user
$user = $this->trongate_tokens->get_user_obj();
if ($user === false) {
redirect('login/login');
}
// Fetch comment
$comment = $this->db->get_where($comment_id, 'comments');
if (!$comment) {
http_response_code(404);
die('Comment not found');
}
// Check ownership
if ($comment->trongate_user_id === $user->trongate_user_id) {
return $user->token; // Owner can edit/delete
}
// Check admin status
if ($user->user_level === 'admin') {
return $user->token; // Admin can edit/delete
}
// Access denied
http_response_code(403);
die('You do not have permission to ' . $scenario);
default:
return false;
}
}The make_sure_allowed() method name, as shown above, uses to prevent URL invocation.
For more information about these topics check out:
Forum_comments.php (Controller)
Using the scenarios in your controller:
<?php
class Forum_comments extends Trongate {
public function view(int $comment_id): void {
// Anyone can read
$this->trongate_security->make_sure_allowed('read comment');
$data['comment'] = $this->db->get_where($comment_id, 'comments');
$data['view_file'] = 'view_comment';
$this->templates->public($data);
}
public function create(): void {
// Must be logged in
$token = $this->trongate_security->make_sure_allowed('create comment');
$data['view_file'] = 'create_comment';
$this->templates->members_area($data);
}
public function edit(int $comment_id): void {
// Check ownership or admin rights
$this->trongate_security->make_sure_allowed('edit comment', [
'comment_id' => $comment_id
]);
$data['comment'] = $this->db->get_where($comment_id, 'comments');
$data['view_file'] = 'edit_comment';
$this->templates->members_area($data);
}
public function delete(int $comment_id): void {
// Check ownership or admin rights
$this->trongate_security->make_sure_allowed('delete comment', [
'comment_id' => $comment_id
]);
$this->db->delete($comment_id, 'comments');
set_flashdata('Comment deleted successfully');
redirect('forum_comments/index');
}
}This example assumes you have public and members_area templates created.
Using $this->login->make_sure_allowed() Directly
In your own controllers, you can also call the login module directly to check authentication without going through the security module:
// Check if the current user is logged in as an administrator (user level 1)
$token = $this->login->make_sure_allowed();
if ($token === false) {
redirect('login/login');
}The login->make_sure_allowed() method checks the token, validates the user level, and returns the token string if valid, or false if not. In development mode, it provides convenience features; in production, it always requires proper authentication.
The $params Array
The optional $params array allows fine-grained control:
$params = [
'comment_id' => 42,
'action' => 'edit',
'user_role' => 'moderator'
];
$this->trongate_security->make_sure_allowed('moderate forum', $params);Pass any data your scenario needs to make authorization decisions.
Building Your Own Scenarios
To add custom scenarios:
- Open
Trongate_security.php - Add a new case to the switch statement
- Either handle inline OR delegate to another module
- Return appropriate value (token, boolean, object, etc.)
Example: Premium Content
case 'premium content':
$user = $this->trongate_tokens->get_user_obj();
if ($user === false) {
redirect('login/login');
}
// Check if user has premium subscription
$sql = 'SELECT * FROM subscriptions WHERE trongate_user_id = ? AND status = ?';
$subscription = $this->db->query_bind($sql, [$user->trongate_user_id, 'active'], 'object');
if (empty($subscription)) {
redirect('subscriptions/upgrade');
}
return $user; // Return full user object with subscription infoWhy Scenarios Win
- Centralized security logic - All authorization in one place
- Consistent patterns - Same method call everywhere
- Easy to audit - Review security in one file
- Flexible delegation - Complex logic lives in appropriate modules
- Testable - Mock scenarios for unit tests
Common Patterns
Pattern 1: Public Access
case 'public page':
return true;Pattern 2: Simple Member Check
case 'members area':
$token = $this->trongate_tokens->attempt_get_valid_token(2);
if ($token === false) {
redirect('login/login');
}
return $token;Pattern 3: Delegate to Module
case 'complex scenario':
$result = $this->custom_module->make_sure_allowed($scenario, $params);
return $result;- Use descriptive scenario names -
'edit comment'not'scenario_7' - Delegate complex logic - Keep switch statement clean, push details to modules
- Return consistent types per scenario - Do not mix tokens and booleans for same scenario
- Document your scenarios - Add comments explaining what each scenario protects
- Test thoroughly - Especially ownership checks and edge cases
We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.
Share your thoughts in the Documentation Feedback.