Problem
When a user's session expires from inactivity, page navigations correctly redirect to the login page. However, AJAX requests (e.g. bootstrap-table server-side search/sort calls) do not — they fail silently or malfunction instead of prompting re-authentication.
Example symptom: on a bootstrap-table list page, clicking a column sort header while the session is expired makes all rows disappear with no error message, giving the impression that sorting itself is broken. The real cause is session expiry, not the sort logic.
Root cause
app/Filters/IsLoggedIn.php is a global filter (applied to all routes except login/migrate) that unconditionally throws a RedirectException when the session is invalid:
public function before(RequestInterface $request, $arguments = null)
{
$employee = model(Employee::class);
if (!$employee->is_logged_in()) {
throw new RedirectException('login');
}
}
This has no AJAX-awareness. CodeIgniter converts the exception into a plain HTTP 302 redirect to /login for every request type, including XHR calls.
For a normal page navigation this works fine — the browser follows the redirect and shows the login page.
For an AJAX call (e.g. bootstrap-table's server-side search/sort endpoint), the browser's XHR transparently follows the 302 and fetches the login page's HTML as the response body. The calling code expects JSON (e.g. {total, rows}), so parsing fails silently and the table just renders empty. No error is surfaced to the user.
This is not specific to any one page or table — it's a global filter, so it affects every AJAX-backed list/search endpoint in the app.
There is currently no AJAX-aware 401 handling anywhere in the codebase: no isAJAX() check in the auth filter, and no global jQuery ajaxError/ajaxSetup interceptor client-side to catch an auth failure and force a redirect.
Proposed solution
- Server-side: In
IsLoggedIn::before(), check $request->isAJAX(). If true, return a JSON response with HTTP 401 instead of throwing RedirectException. Keep the existing redirect behavior for normal navigations.
- Client-side: Add a global AJAX response handler (e.g.
$.ajaxSetup({ statusCode: { 401: ... } }), or a bootstrap-table onLoadError handler) that, on receiving a 401, forces a full-page redirect to the login URL.
This way, an expired session during an AJAX call results in a clear redirect to login rather than a confusing, silent UI failure.
Problem
When a user's session expires from inactivity, page navigations correctly redirect to the login page. However, AJAX requests (e.g. bootstrap-table server-side search/sort calls) do not — they fail silently or malfunction instead of prompting re-authentication.
Example symptom: on a bootstrap-table list page, clicking a column sort header while the session is expired makes all rows disappear with no error message, giving the impression that sorting itself is broken. The real cause is session expiry, not the sort logic.
Root cause
app/Filters/IsLoggedIn.phpis a global filter (applied to all routes exceptlogin/migrate) that unconditionally throws aRedirectExceptionwhen the session is invalid:This has no AJAX-awareness. CodeIgniter converts the exception into a plain HTTP 302 redirect to
/loginfor every request type, including XHR calls.For a normal page navigation this works fine — the browser follows the redirect and shows the login page.
For an AJAX call (e.g. bootstrap-table's server-side search/sort endpoint), the browser's XHR transparently follows the 302 and fetches the login page's HTML as the response body. The calling code expects JSON (e.g.
{total, rows}), so parsing fails silently and the table just renders empty. No error is surfaced to the user.This is not specific to any one page or table — it's a global filter, so it affects every AJAX-backed list/search endpoint in the app.
There is currently no AJAX-aware 401 handling anywhere in the codebase: no
isAJAX()check in the auth filter, and no global jQueryajaxError/ajaxSetupinterceptor client-side to catch an auth failure and force a redirect.Proposed solution
IsLoggedIn::before(), check$request->isAJAX(). If true, return a JSON response with HTTP 401 instead of throwingRedirectException. Keep the existing redirect behavior for normal navigations.$.ajaxSetup({ statusCode: { 401: ... } }), or a bootstrap-tableonLoadErrorhandler) that, on receiving a 401, forces a full-page redirect to the login URL.This way, an expired session during an AJAX call results in a clear redirect to login rather than a confusing, silent UI failure.