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:

  1. App startAuthManager::initialize() reads any persisted session from disk (load_session()).
  2. If the session is authenticated and contains a valid api_key, UI components (e.g., ToolBar, NavigationBar) automatically call SessionGuard::start().
  3. Login flow – UI calls AuthManager::login(email, password, force). On success AuthManager updates session_, emits auth_state_changed() and login_succeeded().
  4. PulseSessionGuard sends a session_pulse every PULSE_INTERVAL_MS.
    • 401/403 → token may be stale → AuthManager::attempt_session_recovery() is invoked.
    • valid:false in body → same recovery path.
  5. Recovery – If the backend can refresh the session (e.g., via a refresh token), AuthManager restores session_ and emits auth_state_changed().
  6. Failure – If recovery fails, SessionGuard emits session_expired(), stops its timer, and forces a logout via AuthManager::logout(). The UI receives logged_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

File Role
[AuthManager.h](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/auth/AuthManager.h) Declares the singleton, session data accessor, public auth methods, and signals.
[AuthManager.cpp](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/auth/AuthManager.cpp) Implements login, logout, session persistence, recovery, and signal emission.
[AuthApi.h](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/auth/AuthApi.h) Stateless HTTP wrapper for auth endpoints, used by AuthManager and SessionGuard.
[SessionGuard.h](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/auth/SessionGuard.h) Declares the watchdog timer and its public API.
[SessionGuard.cpp](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/auth/SessionGuard.cpp) Implements the pulse loop, recovery handling, and auto‑logout trigger.
UI components (e.g., ToolBar.cpp, NavigationBar.cpp, ProfileScreen.cpp) Show how the rest of the application observes AuthManager signals and reacts to logout.

Summary

  • Use AuthManager as the central singleton for all authentication state, session persistence, and signal emission.
  • Deploy SessionGuard to automatically monitor session validity via periodic session_pulse calls to the backend.
  • Handle expiry by listening to AuthManager::auth_state_changed or SessionGuard::session_expired signals to update UI state and redirect to login.
  • Customize behavior by modifying PULSE_INTERVAL_MS, overriding attempt_session_recovery, or extending SessionData for additional fields.
  • Key files are located in fincept-qt/src/auth/ and follow the AuthManagerSessionGuardAuthApi hierarchy.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →