fix: set cookieSecure=False so session persists on HTTP (localhost)

The UserSession cookie was defaulting to secure=True which prevents
browsers from sending it on non-HTTPS connections. This caused the
dashboard to redirect back to login on every click.

Verified with Playwright: login, dashboard link click, and navbar
navigation all preserve the session correctly.
This commit is contained in:
2026-07-16 07:48:10 -04:00
parent dbfe3a7c66
commit bcdda0754b
2 changed files with 58 additions and 32 deletions
+1
View File
@@ -31,6 +31,7 @@ newtype UserSession = UserSession
instance Session UserSession where instance Session UserSession where
cookiePath = Just "/" cookiePath = Just "/"
cookieSecure = False
instance Default UserSession where instance Default UserSession where
def = UserSession 0 def = UserSession 0
+55 -30
View File
@@ -2,46 +2,71 @@ const { chromium } = require('playwright');
(async () => { (async () => {
const browser = await chromium.launch({ headless: true }); const browser = await chromium.launch({ headless: true });
const page = await browser.newPage(); const context = await browser.newContext();
const page = await context.newPage();
// Collect ALL console messages page.on('console', msg => console.log('CONSOLE:', msg.type(), msg.text().substring(0, 150)));
page.on('console', msg => console.log('CONSOLE:', msg.type(), msg.text()));
page.on('pageerror', err => console.log('PAGE ERROR:', err.message)); page.on('pageerror', err => console.log('PAGE ERROR:', err.message));
// Listen for network responses // Step 1: Load login page
page.on('response', resp => { console.log('\n=== Step 1: Load login page ===');
if (resp.url().includes('/rlogin') || resp.url().includes('websocket')) {
console.log('RESPONSE:', resp.status(), resp.url().substring(0, 50));
}
});
await page.goto('http://localhost:8080/rlogin', { waitUntil: 'networkidle', timeout: 10000 }); await page.goto('http://localhost:8080/rlogin', { waitUntil: 'networkidle', timeout: 10000 });
console.log('URL:', page.url());
// Check the HTML // Step 2: Submit login form
const html = await page.content(); console.log('\n=== Step 2: Submit login ===');
console.log('Has "Welcome":', html.includes('Welcome'));
console.log('Has "lfEmail":', html.includes('lfEmail'));
console.log('Has form action:', html.includes('data-onsubmit'));
await page.fill('input[name="lfEmail"]', 'alice@demo.com'); await page.fill('input[name="lfEmail"]', 'alice@demo.com');
await page.fill('input[name="lfPassword"]', 'password123'); await page.fill('input[name="lfPassword"]', 'password123');
console.log('Clicking submit...');
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
// Wait to see what happens console.log('URL after submit:', page.url());
await page.waitForTimeout(4000);
const newHtml = await page.content();
console.log('After submit URL:', page.url());
console.log('Has "Invalid":', newHtml.includes('Invalid'));
console.log('Has "Logged In":', newHtml.includes('Logged In'));
console.log('Has "Redirecting":', newHtml.includes('Redirecting'));
console.log('Has "Dashboard":', newHtml.includes('Dashboard'));
// Check cookies // Check cookies
const cookies = await page.context().cookies(); const cookies = await context.cookies();
console.log('Cookies:', JSON.stringify(cookies.map(c => c.name + '=' + c.value))); console.log('Cookies:', JSON.stringify(cookies.map(c => ({ name: c.name, value: c.value.substring(0, 20), domain: c.domain, path: c.path }))));
// Check content
const content = await page.content();
console.log('Has "Go to Dashboard":', content.includes('Go to Dashboard'));
console.log('Has "Logged In":', content.includes('Logged In'));
// Step 3: Click "Go to Dashboard"
console.log('\n=== Step 3: Click Go to Dashboard ===');
const dashLink = await page.$('a[href="/rdashboard"]');
if (dashLink) {
console.log('Found dashboard link');
await dashLink.click();
await page.waitForTimeout(3000);
} else {
console.log('No dashboard link found, navigating directly');
await page.goto('http://localhost:8080/rdashboard', { waitUntil: 'networkidle', timeout: 10000 });
}
console.log('URL after dashboard:', page.url());
const dashContent = await page.content();
console.log('Has "Welcome Back":', dashContent.includes('Welcome Back'));
console.log('Has "Dashboard":', dashContent.includes('Dashboard'));
console.log('Has "Overdue":', dashContent.includes('Overdue'));
console.log('Has "No households":', dashContent.includes('No households'));
// Step 4: Check what happens when clicking navbar Dashboard
console.log('\n=== Step 4: Click navbar Dashboard ===');
const navLinks = await page.$$('a');
for (const link of navLinks) {
const href = await link.getAttribute('href');
const text = await link.textContent();
if (text && text.trim() === 'Dashboard') {
console.log('Found navbar Dashboard link:', href);
await link.click();
await page.waitForTimeout(3000);
break;
}
}
console.log('URL after navbar click:', page.url());
const navContent = await page.content();
console.log('Has "Welcome Back":', navContent.includes('Welcome Back'));
console.log('Has "Overdue":', navContent.includes('Overdue'));
await browser.close(); await browser.close();
console.log('\nDone.');
})().catch(e => { console.error('FAIL:', e.message); process.exit(1); }); })().catch(e => { console.error('FAIL:', e.message); process.exit(1); });