How to Manage Sessions and Implement Auto-Logout on Authentication Expiry in FinceptTerminal
FinceptTerminal manages sessions through the AuthManager singleton for state persistence and SessionGuard for periodic validation, automatically logging users out when the backend returns HTTP 401/403 or "valid": false.
FinceptTerminal provides a robust authentication architecture that enables developers to manage sessions securely and implement auto-logout on authentication expiry. The system's design centers on two primary components: the AuthManager singleton, which maintains the current SessionData and handles persistence, and the SessionGuard watchdog, which monitors session validity through periodic pulses to the backend.
Core Architecture
The session management system relies on three primary components working in concert:
| Component | Responsibility | Key API / Signals | Typical Usage |
|---|---|---|---|
AuthManager |
Central state machine; stores session_ (SessionData). Provides methods for login, signup, OTP/MFA verification, password reset, logout, session init/recovery, and refresh of user data. Emits a rich set of signals to inform the UI of auth state changes. |
auth_state_changed(), login_succeeded(), login_failed(), session_expired(), logged_out(), terminal_unlocked() … |
UI widgets obtain the singleton via AuthManager::instance() and read session() or connect to the signals. |
SessionGuard |
Periodic background task (Qt QTimer) that calls AuthApi::session_pulse. Handles HTTP 401/403 or a "valid": false response, attempts session recovery, and on failure logs out the user automatically. |
Emits its own session_expired() (mirrored from AuthManager) and stops the timer when the session becomes unauthenticated. |
Instantiated once (e.g. in the main window) and left running for the lifetime of the app. |
AuthApi (stateless) |
Thin wrapper around HTTP calls (login, session_pulse, logout, …). All network interaction for auth lives here; the API key is stored in the shared HttpClient. |
No signals – callbacks (std::function<void(ApiResponse)>). |
Called by AuthManager and SessionGuard to talk to the backend. |
Session Lifecycle
Understanding the lifecycle is essential to manage sessions effectively:
- App start →
AuthManager::initialize()reads any persisted session from disk (load_session()). - If the session is authenticated and contains a valid
api_key, UI components (e.g.,ToolBar,NavigationBar) automatically callSessionGuard::start(). - Login flow – UI calls
AuthManager::login(email, password, force). On successAuthManagerupdatessession_, emitsauth_state_changed()andlogin_succeeded(). - Pulse –
SessionGuardsends asession_pulseeveryPULSE_INTERVAL_MS.- 401/403 → token may be stale →
AuthManager::attempt_session_recovery()is invoked. valid:falsein body → same recovery path.
- 401/403 → token may be stale →
- Recovery – If the backend can refresh the session (e.g., via a refresh token),
AuthManagerrestoressession_and emitsauth_state_changed(). - Failure – If recovery fails,
SessionGuardemitssession_expired(), stops its timer, and forces a logout viaAuthManager::logout(). The UI receiveslogged_out()/auth_state_changed()and redirects the user to the login screen.
Implementation Examples
Accessing the Session and Reacting to Changes
UI components connect to AuthManager signals to update their state dynamically:
// Example: UI toolbar that shows the user’s name and logout button
#include "auth/AuthManager.h"
ToolBar::ToolBar(QWidget *parent) : QWidget(parent) {
connect(&auth::AuthManager::instance(),
&auth::AuthManager::auth_state_changed,
this,
&ToolBar::refresh_all);
refresh_all();
}
void ToolBar::refresh_all() {
const auto &s = auth::AuthManager::instance().session();
userLabel_->setText(s.username);
logoutBtn_->setEnabled(s.authenticated);
}
Source: [fincept-qt/src/ui/navigation/ToolBar.cpp](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/ui/navigation/ToolBar.cpp)
Starting the Auto-Logout Watchdog
Instantiate SessionGuard in your main window to enable automatic session validation:
// Usually instantiated in the main window constructor
#include "auth/SessionGuard.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
sessionGuard_ = new auth::SessionGuard(this);
// SessionGuard automatically starts when a valid session appears
}
Source: [fincept-qt/src/auth/SessionGuard.cpp](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/auth/SessionGuard.cpp)
Handling Expired Sessions
The SessionGuard automatically triggers logout when the server rejects the session pulse:
void SessionGuard::check_pulse() {
// …
if (!r.success && (r.status_code == 401 || r.status_code == 403)) {
// Attempt recovery…
AuthManager::instance().attempt_session_recovery([this](bool recovered) {
if (!recovered) {
stop(); // stop further pulses
emit session_expired(); // UI can also listen to this
AuthManager::instance().logout(); // forces full logout
}
});
}
}
Source: same file as above.
Full Logout Implementation
The AuthManager clears local state regardless of server response:
void AuthManager::logout() {
if (is_logging_out_) return;
is_logging_out_ = true;
AuthApi::instance().logout([this](ApiResponse r) {
// Regardless of server response we clear the local session
clear_session();
set_loading(false);
is_logging_out_ = false;
emit logged_out();
emit auth_state_changed();
});
}
Source: [fincept-qt/src/auth/AuthManager.cpp](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/auth/AuthManager.cpp)
Customization Guide
| Goal | What to modify | Where |
|---|---|---|
| Change pulse interval | Adjust PULSE_INTERVAL_MS constant in SessionGuard.h |
fincept-qt/src/auth/SessionGuard.h |
| Add custom recovery logic (e.g., refresh token) | Override AuthManager::attempt_session_recovery or plug a new API endpoint in AuthApi::session_pulse |
AuthManager.cpp & AuthApi.cpp |
| Show a UI warning before auto‑logout | Connect to SessionGuard::session_expired in your main UI and present a modal dialog |
Your application’s main window or a dedicated SessionExpiredDialog |
| Persist additional session fields (e.g., device fingerprint) | Extend SessionData in AuthTypes.h and update AuthManager::save_session/load_session |
fincept-qt/src/auth/AuthTypes.h & AuthManager.cpp |
Key Files Reference
Summary
- Use
AuthManageras the central singleton for all authentication state, session persistence, and signal emission. - Deploy
SessionGuardto automatically monitor session validity via periodicsession_pulsecalls to the backend. - Handle expiry by listening to
AuthManager::auth_state_changedorSessionGuard::session_expiredsignals to update UI state and redirect to login. - Customize behavior by modifying
PULSE_INTERVAL_MS, overridingattempt_session_recovery, or extendingSessionDatafor additional fields. - Key files are located in
fincept-qt/src/auth/and follow theAuthManager→SessionGuard→AuthApihierarchy.
Frequently Asked Questions
How does FinceptTerminal detect when a session has expired?
The SessionGuard component sends a periodic session_pulse to the backend every PULSE_INTERVAL_MS. If the server responds with HTTP 401/403 or a JSON body containing "valid": false, the guard initiates recovery via AuthManager::attempt_session_recovery(). When recovery fails, it emits session_expired() and calls AuthManager::logout() to clear local state.
Where is session data stored between application restarts?
AuthManager persists session data to disk via save_session() and reloads it on startup through load_session() inside initialize(). The storage location and serialization format are handled within AuthManager.cpp, allowing the session to survive application restarts while the SessionData structure in AuthTypes.h defines the fields being persisted.
Can I customize the auto-logout timer interval?
Yes. The pulse interval is controlled by the PULSE_INTERVAL_MS constant in fincept-qt/src/auth/SessionGuard.h. Adjusting this value changes how frequently the client validates the session with the server. For recovery customization, override AuthManager::attempt_session_recovery to implement refresh token logic or other backend-specific renewal mechanisms.
How should the UI respond to automatic logout?
UI components should connect to AuthManager::auth_state_changed or SessionGuard::session_expired signals. When these fire, the application should redirect to the login screen, disable sensitive controls, or display a modal dialog. The ToolBar.cpp implementation demonstrates reading AuthManager::instance().session() to dynamically update visibility of user-specific elements based on authentication state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →