Authentication Testing Runbook (Manual)
1. Overview
This document outlines the sequential testing flow for the Reshma-Core Two-Token Authentication system. These tests verify both the "Happy Path" (expected behavior) and critical security edge cases.
Recommended Tools: Thunder Client (VS Code) or Postman.
Note: These tools are required over cURL because they automatically manage the HttpOnly refresh cookies necessary for session testing.
2. Prerequisites & Environment Setup
Before beginning the test suite, verify the infrastructure is actively running:
- MongoDB: Running locally or via Atlas.
- Redis: Running locally (
redis-cli ping->PONG). - Background Workers: Ensure
npm run devhas booted both the Express server AND the BullMQ email worker. - Base URL:
http://localhost:5000/api/v1
3. The "Happy Path" (Sequential Test Suite)
These tests MUST be executed in this exact order, as each step relies on the state generated by the previous step.
Test 1: Account Registration
- Action: Send
POST /auth/register - Payload (JSON):
{"firstname": "Test","lastname": "User","email": "test@example.com","password": "SecurePassword123!"}
- Expected Result:
201 Created. - Side-Effect Verification:
- Check the server terminal: The Winston logger should print the generated 6-digit OTP.
- Check MongoDB: The user document should exist with
isEmailVerified: false.
Test 2: OTP Verification (Session Grant)
- Action: Send
POST /auth/verify-otp - Payload (JSON):
{"email": "test@example.com","otp": "123456" // Replace with OTP from Test 1}
- Expected Result:
200 OK. The JSON response must contain theuserobject and theaccessToken. - Side-Effect Verification:
- CRITICAL: Check the "Cookies" tab in Thunder Client. A
refreshTokencookie MUST be present. - Check Redis:
GET otp:test@example.comshould returnnil(OTP deleted to prevent replay attacks). - Check MongoDB: User
isEmailVerifiedshould now betrue.
- CRITICAL: Check the "Cookies" tab in Thunder Client. A
Test 3: Standard Login
- Action: Send
POST /auth/login - Payload (JSON):
{"email": "test@example.com","password": "SecurePassword123!"}
- Expected Result:
200 OK. Receives a newaccessToken.
Test 4: Silent Token Refresh
- Action: Send
GET /auth/refresh(No Body, No Auth Headers). - Expected Result:
200 OK. The server reads the HttpOnly cookie automatically and returns a brand newaccessTokenin the JSON response.
Test 5: Secure Logout
- Action: Send
GET /auth/logout - Headers:
Authorization: Bearer <PASTE_ACCESS_TOKEN_HERE> - Expected Result:
200 OK. - Side-Effect Verification:
- Check the "Cookies" tab: The
refreshTokenshould be overwritten with "loggedout" and expired. - Check Redis: Run
KEYS *. You should see a new key prefixed withblacklist:, proving the session is permanently burned.
- Check the "Cookies" tab: The
4. Security & Edge Case Testing (Negative Tests)
These tests ensure the API fails gracefully and securely under malicious or incorrect conditions.
Edge Case 1: Zod Payload Firewall
- Action: Send
POST /auth/registerwith an invalid email (test@com) and a weak password (123). - Expected Result:
400 Bad Request. The responsemessagemust clearly list both the email format error and the password strength error.
Edge Case 2: Unverified Login Block
- Action: Register a completely new email (Test 1), but do not verify the OTP. Attempt to call
POST /auth/loginwith those credentials. - Expected Result:
403 Forbiddenwith the message: "Please verify your email address before logging in."
Edge Case 3: Replay Attack Prevention
- Action: Attempt to call
POST /auth/verify-otpusing an OTP that has already been successfully verified. - Expected Result:
400 Bad Requestwith "Invalid or expired OTP."
Edge Case 4: Protected Route Gateway (Missing Token)
- Action: Call
GET /auth/logoutbut do not provide the Bearer token in the Auth tab. - Expected Result:
401 Unauthorizedwith "You are not logged in".
Edge Case 5: The Blacklist Check
-
Action:
- Login successfully.
- Logout successfully (this blacklists the refresh token).
- Manually re-add the old
refreshTokenback into Thunder Client's cookie tab. - Call
GET /auth/refresh.
-
Expected Result:
401 Unauthorizedwith "Session revoked." (Proves the Redis blacklist is actively protecting the route).