Step-by-Step Guide — Follow each step exactly as written. Every value you need to type is spelled out. Do not improvise.

TC-AUTH-005: Session Management (Detailed)

Module: Authentication & Identity - Session Management

Admin Test User: admin@rcme.membervu.com / Admin123! (Admin User)

Member Test User: testmember@rcme.membervu.com / Member123! (Maria Cruz)

Treasurer Test User: treasurer@demo.membervu.com / Treasurer123! (Ana Reyes)

Events Mgr Test User: events@demo.membervu.com / Events123! (Carlos Garcia)

URLs for this test:
Frontend: https://stg-rcme.membervu.com
🆕 New steps this release (2026-06-19 → 2026-07-01): TC-SESS-07 (deactivate → immediate 401, #446), TC-SESS-08 (deep-link returnUrl, #346), TC-SESS-09 (open-redirect rejection, #360), TC-SESS-10 (membership-application rate limit, #501) — appended after the existing scenarios below. Do not delete the older ones.

TC-SESS-01: Login and Logout Flow

Purpose: Verify the basic login and logout flow works correctly.

StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 Open your browser and go to:
https://stg-rcme.membervu.com/login
The MemberVu login page loads with Email and Password fields and a "Sign In" button. https://stg-rcme.membervu.com/login
2 Enter email: admin@rcme.membervu.com
Enter password: Admin123!

Click "Sign In".
Login succeeds. The admin dashboard loads. You see admin navigation items in the sidebar (e.g., "Admin", "Members", "Settings"). Email: admin@rcme.membervu.com
Password: Admin123!
3 Click on your user avatar or name in the top-right corner of the page to open the user menu. A dropdown menu appears with options like "Profile", "Settings", and "Logout" (or "Sign Out"). -
4 Click "Logout" (or "Sign Out"). You are redirected to the login page:
https://stg-rcme.membervu.com/login
-
5 Try to access a protected page directly by entering this URL:
https://stg-rcme.membervu.com/dashboard
You are redirected back to the login page. You cannot access the dashboard without logging in. https://stg-rcme.membervu.com/dashboard
PASS if: Login shows dashboard, logout redirects to login, and protected pages are not accessible after logout.

TC-SESS-02: Session Persistence (Tab Reopen)

Purpose: Verify that a session persists when closing and reopening a browser tab.

StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 Go to https://stg-rcme.membervu.com/login

Enter email: admin@rcme.membervu.com
Enter password: Admin123!

Click "Sign In".
Login succeeds. Dashboard loads. Email: admin@rcme.membervu.com
Password: Admin123!
2 Close the browser tab (NOT the entire browser window — just the tab). Do NOT log out first. The tab closes. -
3 Open a new tab in the same browser. Go to:
https://stg-rcme.membervu.com/dashboard
The dashboard loads WITHOUT requiring you to log in again. Your session persisted via localStorage. https://stg-rcme.membervu.com/dashboard
4 Log out from this new tab. Redirected to login page. -
PASS if: Session persists after closing and reopening a tab (without explicit logout).

TC-SESS-03: Multi-Tab Session

Purpose: Verify that authentication state is shared across multiple browser tabs.

StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 In Tab 1, go to:
https://stg-rcme.membervu.com/login

Enter email: admin@rcme.membervu.com
Enter password: Admin123!

Click "Sign In".
Login succeeds in Tab 1. Dashboard loads. Email: admin@rcme.membervu.com
Password: Admin123!
2 Open a new Tab 2 in the same browser. Go to:
https://stg-rcme.membervu.com/dashboard
Tab 2 also shows the dashboard — you are authenticated in both tabs because the session token is stored in localStorage (shared across tabs). https://stg-rcme.membervu.com/dashboard
3 In Tab 1, click the user menu and click "Logout". Tab 1 redirects to the login page. -
4 Switch to Tab 2. Click on any navigation link (e.g., "Members" or "Profile") to trigger a page navigation or API call. Tab 2 should detect the logout. It will either:
- Automatically redirect to the login page, or
- Show an "Unauthorized" error and redirect to login, or
- Show the login page on the next navigation.

The user should NOT be able to continue using the app in Tab 2 after logging out in Tab 1.
-
PASS if: Both tabs share authentication state, and logout in Tab 1 is detected in Tab 2.

TC-SESS-04: Expired Session

SKIP — This test requires waiting for the JWT token to expire (typically 1 hour or more) or requires manual token manipulation via browser developer tools.

What would happen: When the JWT access token expires, the next API call would return a 401 Unauthorized response. The frontend would either:
- Attempt to refresh the token using a refresh token (if implemented), or
- Redirect the user to the login page with a message like "Your session has expired. Please log in again."

TC-SESS-05: Role-Based Menu Visibility

Purpose: Verify that different roles see different navigation menus and access levels.

StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 Go to https://stg-rcme.membervu.com/login

Enter email: admin@rcme.membervu.com
Enter password: Admin123!

Click "Sign In".
Admin dashboard loads. The sidebar shows admin-specific navigation items such as:
- "Admin" section or menu
- "Members" (admin view)
- "Settings"
- "Billing" / "Invoices"
- "Communications" / "Broadcasts"
Email: admin@rcme.membervu.com
Password: Admin123!
2 Note the navigation items visible to the admin. Write them down or take a screenshot. Then click "Logout". Redirected to login page. -
3 Log in as a regular member:
Email: testmember@rcme.membervu.com
Enter password: Member123!

Click "Sign In".
Member dashboard loads. The sidebar shows member-specific navigation items such as:
- "Dashboard"
- "My Profile"
- "Member Directory"
- "My Invoices"

Admin-specific items (like "Admin", "Settings", "Communications") should NOT be visible.
Email: testmember@rcme.membervu.com
Password: Member123!
4 Verify the "Admin" menu or section is NOT visible in the sidebar. Log out. The Admin section is not shown to a regular member. -
5 Log in as treasurer:
Email: treasurer@demo.membervu.com
Enter password: Treasurer123!

Click "Sign In".
Dashboard loads. The sidebar shows treasurer-specific items. You should see billing/financial related menu items. Admin-only items may or may not be visible depending on the Treasurer's permissions. Email: treasurer@demo.membervu.com
Password: Treasurer123!
6 Note any unique menu items visible to the Treasurer role. Log out. Treasurer-specific navigation noted. -
7 Log in as events manager:
Email: events@demo.membervu.com
Enter password: Events123!

Click "Sign In".
Dashboard loads. The sidebar shows event management items. You should see "Events" or event-related menu items. Email: events@demo.membervu.com
Password: Events123!
8 Note any unique menu items visible to the Events Manager role. Log out. Events Manager-specific navigation noted. -
PASS if: Each role sees appropriate navigation items. Admin sees admin menu, member does NOT see admin menu, and specialized roles (Treasurer, Events) see role-appropriate items.

TC-SESS-06: Clear Cookies Forces Re-Login

Purpose: Verify that clearing browser storage forces the user to log in again.

StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 Log in as admin:
Email: admin@rcme.membervu.com
Password: Admin123!
Dashboard loads. Email: admin@rcme.membervu.com
Password: Admin123!
2 Open the browser's Developer Tools (press F12 or right-click > "Inspect").

Go to the "Application" tab (Chrome) or "Storage" tab (Firefox).

Under "Local Storage", find the entry for https://stg-rcme.membervu.com.

Delete all localStorage entries (right-click > "Clear" or select each key and press Delete).
The localStorage entries are cleared (including oneledger_session, oneledger_session_user, app-tenant). -
3 Refresh the page (press F5). You are redirected to the login page. The session tokens were stored in localStorage, and clearing them forces re-authentication. -
PASS if: Clearing localStorage forces redirect to login page.

TC-SESS-07: Deactivate Revokes Sessions Immediately (#446)

Purpose: Verify a deactivated user's still-unexpired access token is rejected on its next request via tokenVersion, not just when the JWT itself expires.

Do NOT deactivate a shared seed test user (e.g. testmember@rcme.membervu.com) — it will break other testers' sessions/tests. Create or use a throwaway test member for this scenario, and reactivate it afterward (see cleanup).
StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 Browser A: Log in as a throwaway ACTIVE test member (not a shared seed account). Leave the tab open and signed in. Login succeeds; dashboard loads. A disposable/test member you created, currently status ACTIVE
2 Browser B (separate session): Log in as admin@rcme.membervu.com / Admin123!. Go to Members, open the same member from Step 1, click Deactivate (calls POST /api/membership/members/:id/deactivate). Confirmation succeeds; the member's status shows Inactive in the admin list. Email: admin@rcme.membervu.com
Password: Admin123!
3 Immediately switch back to Browser A (do NOT wait ~15 min for the access token to naturally expire) and click any navigation link, or refresh the page (e.g. go to /dashboard or trigger any API call such as viewing your profile). The request returns 401 Unauthorized and you are redirected to the login page — immediately, not after a TTL wait. This proves revocation is via tokenVersion check, not JWT expiry. -
PASS if: The still-logged-in Browser A session is rejected with 401 on its very next request after admin deactivation, well before the access token's own expiry.

TC-SESS-08: Deep-Link returnUrl Preserved Through Login (#346)

Purpose: Verify a protected deep link visited while logged out is preserved and honored after login, instead of dumping the user on the generic role-based landing page.

StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 Make sure you are logged out (clear localStorage / cookies if needed). Navigate directly to:
https://stg-rcme.membervu.com/admin/members
You are redirected to the login page with the original path preserved in the query string:
https://stg-rcme.membervu.com/login?redirect=%2Fadmin%2Fmembers
/admin/members
2 Enter email: admin@rcme.membervu.com
Enter password: Admin123!

Click "Sign In".
Login succeeds and you land directly on /admin/members — the deep-linked page — NOT on the role-based default (/admin/dashboard). Email: admin@rcme.membervu.com
Password: Admin123!
3 Log out. Repeat Steps 1–2 with a different deep link, e.g. /admin/broadcasts, logging in as comms@demo.membervu.com / Comms123! this time. Again lands on the exact deep-linked page (/admin/broadcasts), confirming this isn't a one-off/hardcoded path. Email: comms@demo.membervu.com
Password: Comms123!
PASS if: Post-login landing matches the originally-requested deep-linked URL, for more than one path.

TC-SESS-09: Open-Redirect Rejection (#360)

Purpose: Verify a maliciously-crafted redirect query param cannot send a logged-in user off-site.

This is a security assertion — do not skip. The point is that an attacker who gets a victim to click a crafted login link cannot redirect them to an external phishing site after a successful login.
StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 Log out. Navigate to:
https://stg-rcme.membervu.com/login?redirect=%2F%5Cevil.com
(URL-decoded, the redirect value is /\evil.com — a backslash path.)
The login page loads normally — no crash, no error banner. redirect=%2F%5Cevil.com
2 Enter email: testmember@rcme.membervu.com
Enter password: Member123!

Click "Sign In".
Login succeeds. You land on a safe same-site page (/home or the member's role-based default) — you are NOT sent to evil.com or any external host. Check the address bar to confirm the host is still stg-rcme.membervu.com. Email: testmember@rcme.membervu.com
Password: Member123!
3 Log out. Repeat with ?redirect=https%3A%2F%2Fevil.com (absolute URL) and then ?redirect=%2F%2Fevil.com (protocol-relative, no scheme). Both also resolve to a safe same-site page after login — no off-site redirect in either case. redirect=https%3A%2F%2Fevil.com
redirect=%2F%2Fevil.com
PASS if: None of the three malicious redirect variants (backslash path, absolute URL, protocol-relative) ever navigate the browser to evil.com after login.

TC-SESS-10: Membership-Application Rate Limit (#501)

Purpose: Verify the public, unauthenticated membership-application endpoint is throttled to prevent spam.

StepAction (EXACT clicks/typing)Expected Result (EXACT text/behavior)Test Value
1 While logged out, go to the public membership application page and submit one valid application (calls POST /api/membership/apply). Application submits successfully (200/201). Any valid applicant details
2 Immediately submit 4 more valid applications back-to-back from the same browser/IP (5 total so far in this 15-min window). All 5 succeed. If you can inspect response headers, RateLimit-Remaining counts down toward 0. -
3 Submit a 6th application within the same 15-minute window. Rejected with 429 Too Many Requests — message indicates too many attempts. The application is NOT created. -
4 (Local only, to reset) Run docker restart membervu-backend. In-memory limiter clears; a new application succeeds again. (Not available on staging — wait out the 15-min window there instead.) -
PASS if: Exactly 5 applications succeed per 15-min window per IP; the 6th+ get 429, not a silently-dropped/duplicated application.

CLEANUP — Read This Before You Stop

Data changes were made in the new scenarios above.

The original TC-SESS-01 through TC-SESS-06 scenarios only perform login/logout and do not modify data.

Ensure you are fully logged out of both Browser A and Browser B before finishing.