LOGIN / LOGOUT TRANSFER NOTES
=============================

Purpose
-------
Use these notes to move the Electra -> HERP SSO login and shared logout behavior to another setup.

Important: in this HERP work, no Electra repo files were changed. Electra files are listed because they are part of the existing login/logout flow.


LOGIN FLOW FILES
----------------

1. Electra backend
   File:
   D:\xampp\htdocs\git\electra2.0\backend\app\Services\Auth\AuthService.php

   Purpose:
   - On Electra login, creates a one-time HERP SSO token.
   - Stores token in HERP DB table `sso_tokens`.
   - Returns `sso.redirect_url` to Electra frontend.

   Existing important code:

   return [
       'user' => $this->mapUser($user),
       'authorization' => [
           'token' => $user->createToken('auth_token')->plainTextToken,
           'type' => 'bearer',
           'expires_in' => config('sanctum.expiration')
               ? config('sanctum.expiration') * 60
               : null,
       ],
       'sso' => $this->generateHerpSsoToken($user->username),
   ];

   private function generateHerpSsoToken(string $herpUserid): ?array
   {
       try {
           $token     = Str::random(64);
           $expiresAt = now()->addSeconds(60)->format('Y-m-d H:i:s');
           $createdAt = now()->format('Y-m-d H:i:s');

           DB::connection('herp')->table('sso_tokens')->insert([
               'token'       => $token,
               'herp_userid' => $herpUserid,
               'expires_at'  => $expiresAt,
               'used_at'     => null,
               'created_at'  => $createdAt,
           ]);

           $baseUrl = rtrim(config('services.herp.sso_url', env('HERP_SSO_URL', 'http://127.0.0.1/herp/sso_login.php')), '/');

           return [
               'redirect_url' => $baseUrl . '?token=' . $token,
           ];
       } catch (\Throwable $e) {
           return null;
       }
   }


2. Electra frontend
   File:
   D:\xampp\htdocs\git\electra2.0\frontend\src\contexts\AuthProvider.tsx

   Purpose:
   - Receives `sso.redirect_url` from Electra backend login.
   - Opens HERP SSO login in a new browser tab.
   - Provides Electra `/logout` route through `LogoutRoute`.

   Existing important code:

   if (sso?.redirect_url) {
     window.open(sso.redirect_url, "_blank", "noopener,noreferrer");
   }

   export function LogoutRoute() {
     const { logout } = useAuth();
     useEffect(() => {
       logout();
     }, [logout]);
     return null;
   }


3. HERP SSO login entry
   File:
   D:\xampp\htdocs\git\PHP_564\mimhans-3.0\herp\sso_login.php

   Purpose:
   - Accepts `/herp/sso_login.php?token=<token>`.
   - Uses `session_name('CAKEPHP')`.
   - Checks token in HERP `sso_tokens`.
   - Marks token as used.
   - Loads HERP `www_users` data.
   - Builds all required HERP `$_SESSION` values.
   - Redirects to `index.php`.

   Important lines:

   session_name('CAKEPHP');
   session_start();

   $token_result = DB_query(
       "SELECT herp_userid, expires_at, used_at FROM sso_tokens WHERE token = '$token'",
       $db
   );

   DB_query("UPDATE sso_tokens SET used_at = NOW() WHERE token = '$token'", $db);

   $_SESSION['AccessLevel']       = $u[0];
   $_SESSION['CustomerID']        = $u[1];
   $_SESSION['UserBranch']        = $u[5];
   $_SESSION['DefaultPageSize']   = $u[3];
   $_SESSION['UserStockLocation'] = $u[4];
   $_SESSION['ModulesEnabled']    = explode(',', $u[6]);
   $_SESSION['UsersRealName']     = $u[8];
   $_SESSION['Theme']             = $u[9];
   $_SESSION['UserID']            = $u[16];
   $_SESSION['username']          = $u[11];

   header('Location: index.php');
   exit;


LOGOUT FLOW FILES
-----------------

1. HERP header logout link
   File:
   D:\xampp\htdocs\git\PHP_564\mimhans-3.0\herp\includes\header.inc

   Change made:
   Old logout link pointed to old app:

   <a href="<?php echo _ROOT.'userrolls/logout'; ?>" style="color:#c0392b;">

   New logout link points to HERP logout:

   <a href="<?php echo $rootpath; ?>/Logout.php" style="color:#c0392b;">
       <i class="fa fa-power-off" aria-hidden="true"></i>&nbsp;&nbsp; Logout
   </a>


2. HERP logout implementation
   File:
   D:\xampp\htdocs\git\PHP_564\mimhans-3.0\herp\Logout.php

   Purpose:
   - Updates HERP CRM login history sign-out time.
   - Destroys HERP `CAKEPHP` PHP session.
   - Removes HERP session cookie.
   - Clears browser localStorage/sessionStorage for HERP origin.
   - Sends Electra logout signal keys.
   - Loads Electra frontend `/logout` route in hidden iframe.
   - No Electra code change is required because Electra already has `/logout` mapped to `LogoutRoute`.
   - Current Electra frontend URL found in Electra `.env`: `http://192.168.1.21:4000/`.
   - Important caveat found in Electra frontend:
     Electra uses `MemoryRouter` with `initialEntries` from `localStorage.activeRoutePath`.
     Because of that, opening `http://192.168.1.21:4000/logout` from HERP may not always run
     `LogoutRoute`. It only works reliably if Electra's router starts at `/logout`.
     No Electra files were changed here.
   - Attempts to close the HERP tab.
   - Supports API mode for another frontend app:

     POST or GET:
     http://your-herp-host/git/PHP_564/mimhans-3.0/herp/Logout.php?api=1

     Response:
     {"success":true,"message":"HERP logout completed","logged_out_at":"YYYY-MM-DD HH:MM:SS"}

     Optional frontend call from Electra or another app:

     async function logoutBothApps() {
       try {
         await fetch('http://your-herp-host/git/PHP_564/mimhans-3.0/herp/Logout.php?api=1', {
           method: 'POST',
           credentials: 'include',
           keepalive: true
         });
       } catch (e) {}

       // Then run the local app logout.
       localStorage.clear();
       sessionStorage.clear();
       window.location.href = '/logout';
     }

     Notes:
     - Use `credentials: 'include'` so the browser sends the HERP `CAKEPHP` session cookie.
     - `Logout.php?api=1` allows local/LAN origins such as localhost, 127.0.0.1, and 192.168.x.x for CORS.
     - HERP itself logs Electra out by loading Electra's existing `/logout` route in a hidden iframe:

       const frame = document.createElement('iframe');
       frame.style.display = 'none';
       frame.src = 'http://192.168.1.21:4000/logout';
       document.body.appendChild(frame);

     Recommended when Electra and HERP run on different IP/host:
     Use top-level redirect mode so the browser sends the HERP session cookie reliably.

     function logoutBothApps() {
       const herpLogoutUrl = 'http://your-herp-host/git/PHP_564/mimhans-3.0/herp/Logout.php';
       const electraLogoutUrl = window.location.origin + '/logout';

       window.location.href = herpLogoutUrl
         + '?return_url='
         + encodeURIComponent(electraLogoutUrl);
     }

     Flow:
     1. Electra sends the browser to HERP `Logout.php`.
     2. HERP destroys the `CAKEPHP` session.
     3. HERP redirects back to Electra `/logout`.
     4. Electra clears its own frontend/backend session.

   Core replacement code:
   The current HERP file also includes simple CSS for the logout message box. The functional code to move is below.

   <?php
   ob_start();

   $PathPrefix = '';
   session_name('CAKEPHP');

   include($PathPrefix . 'config.php');

   if (isset($SessionSavePath)) {
       session_save_path($SessionSavePath);
   }

   ini_set('session.gc_maxlifetime', $SessionLifeTime);
   ini_set('max_execution_time', $MaximumExecutionTime);

   session_start();

   $lastLoginHistoryId = isset($_SESSION['LastLogin_HistoryId']) ? $_SESSION['LastLogin_HistoryId'] : '';

   if ($lastLoginHistoryId !== '') {
       include($PathPrefix . 'includes/LanguageSetup.php');
       include($PathPrefix . 'includes/ConnectDB.inc');

       if (isset($db)) {
           $historyId = DB_escape_string($lastLoginHistoryId);
           DB_query(
               "UPDATE crm_login_history
                SET sign_outtime = NOW(),
                    id_address = '" . DB_escape_string($_SERVER['REMOTE_ADDR']) . "'
                WHERE id = '$historyId'",
               $db
           );
       }
   }

   $_SESSION = array();

   if (ini_get('session.use_cookies')) {
       $params = session_get_cookie_params();
       setcookie(
           session_name(),
           '',
           time() - 42000,
           $params['path'],
           $params['domain'],
           $params['secure'],
           $params['httponly']
       );
   }

   session_unset();
   session_destroy();

   while (ob_get_level() > 0) {
       ob_end_clean();
   }

   header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
   header('Pragma: no-cache');
   ?>
   <!doctype html>
   <html lang="en">
   <head>
       <meta charset="utf-8">
       <title>Logging out</title>
   </head>
   <body>
       <div class="logout-box">
           <h1>You have been logged out</h1>
           <p id="logout-message">Closing HERP...</p>
           <button type="button" id="close-button">Close tab</button>
       </div>

       <script>
           (function () {
               var now = String(Date.now());
               var accessToken = null;
               var hostOrigin = window.location.protocol + '//' + window.location.hostname;
               var electraOrigins = [
                   window.location.origin,
                   hostOrigin + ':4000'
               ];
               var authKeys = [
                   'accessToken',
                   'user',
                   'sessionExpiryAt',
                   'sessionLastActivityAt',
                   'OPEN_POST_LOGIN_MODAL',
                   'locationId'
               ];

               function safeRun(fn) {
                   try {
                       fn();
                   } catch (error) {}
               }

               function uniqueUrls(urls) {
                   var seen = {};
                   var clean = [];

                   urls.forEach(function (url) {
                       if (!seen[url]) {
                           seen[url] = true;
                           clean.push(url);
                       }
                   });

                   return clean;
               }

               function triggerElectraLogout() {
                   uniqueUrls(electraOrigins).forEach(function (origin) {
                       var iframe = document.createElement('iframe');
                       iframe.src = origin.replace(/\/+$/, '') + '/logout';
                       iframe.title = 'Electra logout';
                       iframe.style.display = 'none';
                       iframe.setAttribute('aria-hidden', 'true');
                       document.body.appendChild(iframe);
                   });
               }

               safeRun(function () {
                   accessToken = localStorage.getItem('accessToken');
               });

               safeRun(function () {
                   if (window.BroadcastChannel) {
                       var channel = new BroadcastChannel('electra-session');
                       channel.postMessage({ type: 'logout', at: Date.now() });
                       channel.close();
                   }
               });

               safeRun(function () {
                   authKeys.forEach(function (key) {
                       localStorage.removeItem(key);
                       sessionStorage.removeItem(key);
                   });
                   localStorage.setItem('sessionLogoutAt', now);
               });

               safeRun(function () {
                   localStorage.clear();
                   sessionStorage.clear();
                   localStorage.setItem('sessionLogoutAt', now);
                   window.setTimeout(function () {
                       localStorage.removeItem('sessionLogoutAt');
                   }, 500);
               });

               safeRun(function () {
                   if (accessToken && window.fetch) {
                       uniqueUrls(electraOrigins).forEach(function (origin) {
                           fetch(origin.replace(/\/+$/, '') + '/api/v1/auth/logout', {
                               method: 'POST',
                               credentials: 'include',
                               keepalive: true,
                               headers: {
                                   Authorization: 'Bearer ' + accessToken,
                                   Accept: 'application/json'
                               }
                           }).catch(function () {});
                       });
                   }
               });

               safeRun(triggerElectraLogout);

               window.setTimeout(function () {
                   window.close();
               }, 1200);

               window.setTimeout(function () {
                   var message = document.getElementById('logout-message');
                   var button = document.getElementById('close-button');

                   if (message) {
                       message.innerHTML = 'HERP and Electra logout was triggered. Your browser blocked automatic tab closing.';
                   }
                   if (button) {
                       button.style.display = 'inline-block';
                       button.onclick = function () {
                           window.close();
                       };
                   }
               }, 1700);
           }());
       </script>
   </body>
   </html>


CONFIG VALUES TO CHECK WHEN MOVING
----------------------------------

1. Electra HERP SSO URL
   Backend env/config should point to target HERP:

   HERP_SSO_URL=http://your-host/herp/sso_login.php

2. Electra frontend URL/port
   Current HERP logout tries:
   - same origin as HERP
   - same host with port 4000

   If Electra runs on another URL or port, update this array in `Logout.php`:

   var electraOrigins = [
       window.location.origin,
       hostOrigin + ':4000'
   ];

3. HERP DB table
   Required table:

   sso_tokens

   Required fields used by code:
   - token
   - herp_userid
   - expires_at
   - used_at
   - created_at


TEST CHECKLIST
--------------

1. Login to Electra.
2. Confirm HERP opens in a new tab through `sso_login.php?token=...`.
3. Confirm HERP lands on `index.php` as the same mapped user.
4. Click HERP profile menu -> Logout.
5. Confirm HERP session is destroyed.
6. Confirm HERP tab closes if browser allows it.
7. Confirm Electra token/localStorage is cleared or Electra redirects to login on refresh/API action.
