/** * Manual Test Script for Logout and Token Verification * Task 14: User Logout & Token Verification * * Run this script with: node test-logout-verify.js * Make sure the server is running on http://localhost:3000 */ const axios = require('axios'); const API_BASE = 'http://localhost:3000/api'; let testToken = null; let testUserId = null; // Helper function for test output function logTest(testNumber, description) { console.log(`\n${'='.repeat(60)}`); console.log(`${testNumber} Testing ${description}`); console.log('='.repeat(60)); } function logSuccess(message) { console.log(`✅ SUCCESS: ${message}`); } function logError(message, error = null) { console.log(`❌ ERROR: ${message}`); if (error) { if (error.response && error.response.data) { console.log(`Response status: ${error.response.status}`); console.log(`Response data:`, JSON.stringify(error.response.data, null, 2)); } else if (error.message) { console.log(`Error details: ${error.message}`); } else { console.log(`Error:`, error); } } } // Test 1: Register a test user to get a token async function test1_RegisterUser() { logTest('1️⃣', 'POST /api/auth/register - Get test token'); try { const userData = { username: `testuser${Date.now()}`, email: `test${Date.now()}@example.com`, password: 'Test@123' }; console.log('Request:', JSON.stringify(userData, null, 2)); const response = await axios.post(`${API_BASE}/auth/register`, userData); console.log('Response:', JSON.stringify(response.data, null, 2)); if (response.data.success && response.data.data.token) { testToken = response.data.data.token; testUserId = response.data.data.user.id; logSuccess('User registered successfully, token obtained'); console.log('Token:', testToken.substring(0, 50) + '...'); } else { logError('Failed to get token from registration'); } } catch (error) { logError('Registration failed', error); } } // Test 2: Verify the token async function test2_VerifyValidToken() { logTest('2️⃣', 'GET /api/auth/verify - Verify valid token'); if (!testToken) { logError('No token available. Skipping test.'); return; } try { const response = await axios.get(`${API_BASE}/auth/verify`, { headers: { 'Authorization': `Bearer ${testToken}` } }); console.log('Response:', JSON.stringify(response.data, null, 2)); if (response.data.success && response.data.data.user) { logSuccess('Token verified successfully'); console.log('User ID:', response.data.data.user.id); console.log('Username:', response.data.data.user.username); console.log('Email:', response.data.data.user.email); console.log('Password exposed?', response.data.data.user.password ? 'YES ❌' : 'NO ✅'); } else { logError('Token verification returned unexpected response'); } } catch (error) { logError('Token verification failed', error.response?.data || error.message); } } // Test 3: Verify without token async function test3_VerifyWithoutToken() { logTest('3️⃣', 'GET /api/auth/verify - Without token (should fail)'); try { const response = await axios.get(`${API_BASE}/auth/verify`); console.log('Response:', JSON.stringify(response.data, null, 2)); logError('Should have rejected request without token'); } catch (error) { if (error.response && error.response.status === 401) { console.log('Response:', JSON.stringify(error.response.data, null, 2)); logSuccess('Correctly rejected request without token (401)'); } else { logError('Unexpected error', error.message); } } } // Test 4: Verify with invalid token async function test4_VerifyInvalidToken() { logTest('4️⃣', 'GET /api/auth/verify - Invalid token (should fail)'); try { const response = await axios.get(`${API_BASE}/auth/verify`, { headers: { 'Authorization': 'Bearer invalid_token_here' } }); console.log('Response:', JSON.stringify(response.data, null, 2)); logError('Should have rejected invalid token'); } catch (error) { if (error.response && error.response.status === 401) { console.log('Response:', JSON.stringify(error.response.data, null, 2)); logSuccess('Correctly rejected invalid token (401)'); } else { logError('Unexpected error', error.message); } } } // Test 5: Verify with malformed Authorization header async function test5_VerifyMalformedHeader() { logTest('5️⃣', 'GET /api/auth/verify - Malformed header (should fail)'); if (!testToken) { logError('No token available. Skipping test.'); return; } try { const response = await axios.get(`${API_BASE}/auth/verify`, { headers: { 'Authorization': testToken // Missing "Bearer " prefix } }); console.log('Response:', JSON.stringify(response.data, null, 2)); logError('Should have rejected malformed header'); } catch (error) { if (error.response && error.response.status === 401) { console.log('Response:', JSON.stringify(error.response.data, null, 2)); logSuccess('Correctly rejected malformed header (401)'); } else { logError('Unexpected error', error.message); } } } // Test 6: Logout async function test6_Logout() { logTest('6️⃣', 'POST /api/auth/logout - Logout'); try { const response = await axios.post(`${API_BASE}/auth/logout`); console.log('Response:', JSON.stringify(response.data, null, 2)); if (response.data.success) { logSuccess('Logout successful (stateless JWT approach)'); } else { logError('Logout returned unexpected response'); } } catch (error) { logError('Logout failed', error.response?.data || error.message); } } // Test 7: Verify token still works after logout (JWT is stateless) async function test7_VerifyAfterLogout() { logTest('7️⃣', 'GET /api/auth/verify - After logout (should still work)'); if (!testToken) { logError('No token available. Skipping test.'); return; } try { const response = await axios.get(`${API_BASE}/auth/verify`, { headers: { 'Authorization': `Bearer ${testToken}` } }); console.log('Response:', JSON.stringify(response.data, null, 2)); if (response.data.success) { logSuccess('Token still valid after logout (expected for stateless JWT)'); console.log('Note: In production, client should delete the token on logout'); } else { logError('Token verification failed unexpectedly'); } } catch (error) { logError('Token verification failed', error.response?.data || error.message); } } // Test 8: Login and verify new token async function test8_LoginAndVerify() { logTest('8️⃣', 'POST /api/auth/login + GET /api/auth/verify - Full flow'); try { // First, we need to use the registered user's credentials // Get the email from the first test const loginData = { email: `test_${testUserId ? testUserId.split('-')[0] : ''}@example.com`, password: 'Test@123' }; // This might fail if we don't have the exact email, so let's just create a new user const registerData = { username: `logintest${Date.now()}`, email: `logintest${Date.now()}@example.com`, password: 'Test@123' }; console.log('Registering new user for login test...'); const registerResponse = await axios.post(`${API_BASE}/auth/register`, registerData); const userEmail = registerResponse.data.data.user.email; console.log('Logging in...'); const loginResponse = await axios.post(`${API_BASE}/auth/login`, { email: userEmail, password: 'Test@123' }); console.log('Login Response:', JSON.stringify(loginResponse.data, null, 2)); const loginToken = loginResponse.data.data.token; console.log('\nVerifying login token...'); const verifyResponse = await axios.get(`${API_BASE}/auth/verify`, { headers: { 'Authorization': `Bearer ${loginToken}` } }); console.log('Verify Response:', JSON.stringify(verifyResponse.data, null, 2)); if (verifyResponse.data.success) { logSuccess('Login and token verification flow completed successfully'); } else { logError('Token verification failed after login'); } } catch (error) { logError('Login and verify flow failed', error); } } // Run all tests async function runAllTests() { console.log('\n'); console.log('╔════════════════════════════════════════════════════════════╗'); console.log('║ Logout & Token Verification Endpoint Tests (Task 14) ║'); console.log('╚════════════════════════════════════════════════════════════╝'); console.log('\nMake sure the server is running on http://localhost:3000\n'); await test1_RegisterUser(); await new Promise(resolve => setTimeout(resolve, 500)); // Small delay await test2_VerifyValidToken(); await new Promise(resolve => setTimeout(resolve, 500)); await test3_VerifyWithoutToken(); await new Promise(resolve => setTimeout(resolve, 500)); await test4_VerifyInvalidToken(); await new Promise(resolve => setTimeout(resolve, 500)); await test5_VerifyMalformedHeader(); await new Promise(resolve => setTimeout(resolve, 500)); await test6_Logout(); await new Promise(resolve => setTimeout(resolve, 500)); await test7_VerifyAfterLogout(); await new Promise(resolve => setTimeout(resolve, 500)); await test8_LoginAndVerify(); console.log('\n'); console.log('╔════════════════════════════════════════════════════════════╗'); console.log('║ All Tests Completed ║'); console.log('╚════════════════════════════════════════════════════════════╝'); console.log('\n'); } // Run tests runAllTests().catch(error => { console.error('\n❌ Fatal error running tests:', error); process.exit(1); });