A login redirect only decides where the browser goes after authentication; it does not protect the destination. An ordinary user can type an administrator URL directly, so every admin page and sensitive endpoint must start or resume the session and enforce the required role before producing output or performing an action.
Redirects are navigation, not authorization
After login, code commonly chooses an administrator or dealer destination from $_SESSION['user_level']. That choice affects the next browser request only. It does not prevent a later request for /admin/admin.php.
Authorization belongs at the boundary of each protected request. If the request lacks a valid authenticated session or the required role, deny it before rendering the page or changing data.
Protect every admin endpoint
Place the session and permission check at the top of each protected PHP page, before any output:
#1 Best Overall
<?php
session_start();
if (($_SESSION['loggedin'] ?? false) !== true) {
header('Location: /login.php');
exit;
}
if (($_SESSION['user_level'] ?? null) !== 50) {
http_response_code(403);
exit('Forbidden');
}
// Administrator-only output and actions follow here.
The value 50 is only the level used in the forum example. Use the role or permission representation defined by your application, and treat a missing, malformed or unexpected value as unauthorized. Apply equivalent checks to form handlers, AJAX routes, download scripts, API endpoints and delete/update actions—not only to pages linked from an admin menu.
Choose the response for a denied request
- Unauthenticated: redirect to the login page when the user has no valid login session.
- Authenticated but insufficiently privileged: return HTTP 403, or redirect to a clearly labelled access-denied page if that is your site’s established behavior.
- Always stop: call
exitor otherwise terminate the request after sending a redirect or denial. Without that stop, later code can still run.
Start or resume the session correctly
session_start() creates a session or resumes the one identified by the request. For cookie-based sessions it must run before output. Each HTTP request that reads $_SESSION must initialize or resume the session, unless PHP session auto-start is explicitly configured.
Rank #2
Session data persists across requests because the client presents the session identifier; it is not because one call in an included file remains active for every future request. If a warning says the session has already started, inspect shared includes or automatic startup and avoid adding another unconditional call to every file. A guarded pattern can be appropriate when ownership of startup is shared:
<?php
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
Fix the post-login branch itself
A separate bug can make the redirect appear wrong. If the dealer destination is assigned unconditionally after the administrator branch, it overwrites the administrator destination. Use mutually exclusive branches, validate the role, and stop after redirecting:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
<?php
$userLevel = $_SESSION['user_level'] ?? null;
if ($userLevel === 50) {
$destination = '/admin/admin.php';
} elseif ($userLevel === 1) {
$destination = '/dealer.php';
} else {
$destination = '/login.php';
}
header('Location: ' . $destination);
exit;
Strict comparisons make the expected type explicit. If the value comes from a database or request and may be a string, normalize and validate it at the authentication boundary rather than relying on loose comparison throughout the application. Never let an unrecognized level fall through to an administrative destination.
Regenerate the session identifier after authentication
When a user successfully authenticates, regenerate the session identifier before marking the session as authenticated. PHP’s security guidance recommends regeneration when privileges are elevated, such as after authentication. A typical sequence is:
Rank #4
<?php
// Credentials have been verified here.
session_start();
session_regenerate_id();
$_SESSION['loggedin'] = true;
$_SESSION['user_id'] = $userId;
$_SESSION['user_level'] = $userLevel;
Session regeneration changes the current identifier while retaining session data. PHP’s function documentation cautions that immediately deleting the old session can cause problems when requests overlap or a network is unstable; follow the current manual and the behavior of your session handler rather than adding an unconditional destructive cleanup.
Use a role model that is easy to audit
Numeric levels can work, but names make checks easier to read and review:
<?php
if (($_SESSION['role'] ?? null) !== 'admin') {
http_response_code(403);
exit('Forbidden');
}
For applications with several independent capabilities, store or retrieve permissions such as users.manage and reports.view instead of inferring every decision from a single hierarchy number. Whatever model you choose, obtain it from trusted server-side authentication data, not from a hidden form field, query parameter or client-controlled cookie.
Session-cached roles versus current permissions
Caching a role in the session is convenient, but a role change made by an administrator may not take effect until sessions are refreshed or invalidated. For high-impact operations, check an authoritative user or permission record on the request, or implement a session version/revocation mechanism. Do not assume that hiding a control in the interface is sufficient protection.
Quick Recap
Test the authorization boundary
- Log in as an administrator and confirm the intended admin destination.
- Log in as a dealer or ordinary user and request the admin URL by typing it directly, using a bookmark, and submitting its forms.
- Verify that unauthenticated requests go to login and authenticated non-admin requests receive the intended denial.
- Call protected AJAX, download and API endpoints directly; confirm they enforce the same rule.
- Try missing, non-numeric, expired and altered role values. None should grant access.
- Confirm that code after a redirect or denial never executes.
- After login, inspect that the session identifier changes and that only the verified server-side identity determines the stored role.
Common mistakes to avoid
- Relying on the login redirect or navigation menu as the security control.
- Reading
$_SESSIONbefore starting or resuming the session. - Assigning a fallback destination after an admin branch, unintentionally overwriting it.
- Using loose comparisons without validating the role’s type and allowed values.
- Checking a page but forgetting its POST handler, file endpoint or API equivalent.
- Sending
header('Location: ...')without terminating execution. - Trusting a role supplied by the browser instead of deriving it from authenticated server-side data.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




