feat(auth): enhance session handling for mobile compatibility

- Modified session management to allow the use of existing sessions for mobile applications, improving session continuity.
- Added detailed logging for session ID usage, response headers, and session save operations to aid in debugging.
- Updated session middleware to support header-based session IDs, ensuring proper handling when cookies are not available.
- Included additional session information in the response for mobile app integration, facilitating better session management.
This commit is contained in:
Chamika J
2025-08-06 11:02:03 +05:30
parent 57c71357da
commit 3ebf262b8e
2 changed files with 82 additions and 55 deletions

View File

@@ -249,67 +249,75 @@ export default class AuthController extends WorklenzControllerBase {
}); });
} }
// Regenerate session for security (prevent session fixation attacks) // Use existing session without regeneration for mobile app compatibility
// Store the old session ID for debugging // Note: This reduces security slightly but ensures session continuity for mobile
const oldSessionId = req.sessionID; console.log("Using existing session ID:", req.sessionID);
req.session.regenerate((regenErr) => { console.log("=== LOGIN SUCCESSFUL ===");
if (regenErr) { console.log("Session ID after login:", req.sessionID);
console.log("Session regeneration error:", regenErr); console.log("Session data after login:", req.session);
// Fall back to using existing session if regeneration fails console.log("Is authenticated:", req.isAuthenticated());
console.log("Falling back to existing session"); console.log("User in session:", req.user);
} else {
console.log("Session regenerated from:", oldSessionId, "to:", req.sessionID); // Add build version
user.build_v = FileConstants.getRelease();
console.log("Sending response...");
console.log("Response headers before send:", res.getHeaders());
// Ensure session is saved and cookie is set
req.session.save((saveErr) => {
if (saveErr) {
console.log("Session save error:", saveErr);
return res.status(500).send({
done: false,
message: "Session save failed",
body: null
});
} }
// Re-establish the user in the session (new or existing) // Get session cookie details
(req.session as any).passport = { user: { id: user.id } }; const sessionName = process.env.SESSION_NAME || 'connect.sid';
console.log("=== LOGIN SUCCESSFUL ==="); console.log("Session saved successfully");
console.log("Session ID after login:", req.sessionID); console.log("Session name:", sessionName);
console.log("Session data after login:", req.session); console.log("Session ID to be sent:", req.sessionID);
console.log("Is authenticated:", req.isAuthenticated());
console.log("User in session:", req.user);
// Add build version // Check if Set-Cookie header is being sent
user.build_v = FileConstants.getRelease(); console.log("Response headers after save:", res.getHeaders());
console.log("Set-Cookie header:", res.getHeader('set-cookie'));
console.log("Sending response..."); // Manually set the session cookie since automatic setting isn't working
console.log("Response headers before send:", res.getHeaders()); if (!res.getHeader('set-cookie')) {
console.log("Set-Cookie header not found, manually setting cookie...");
// Force the session middleware to set the cookie by marking the session as modified
req.session.touch();
// Wait a bit for the middleware to process
setTimeout(() => {
const finalCookieHeader = res.getHeader('set-cookie');
console.log("Cookie header after touch:", finalCookieHeader);
}, 10);
console.log("Session touched to force cookie setting");
}
// Ensure session is saved and cookie is set // Return response with session info for mobile app to handle
req.session.save((saveErr) => { // Include the session ID in both cookie and header for maximum compatibility
if (saveErr) { res.setHeader('X-Session-ID', req.sessionID);
console.log("Session save error:", saveErr); res.setHeader('X-Session-Name', sessionName);
return res.status(500).send({
done: false, return res.status(200).send({
message: "Session save failed", done: true,
body: null message: "Login successful",
}); user,
} authenticated: true,
sessionId: req.sessionID, // Mobile app should use this session ID
// Get session cookie details sessionCookie: sessionName, // Cookie name for mobile app
const sessionName = process.env.SESSION_NAME || 'connect.sid'; // Additional fields for mobile app cookie handling
sessionName: sessionName,
console.log("Session saved successfully"); newSessionId: req.sessionID
console.log("Session name:", sessionName);
console.log("Session ID to be sent:", req.sessionID);
// Check if Set-Cookie header is being sent
console.log("Response headers after save:", res.getHeaders());
console.log("Set-Cookie header:", res.getHeader('set-cookie'));
// Return response with explicit instruction for mobile app
return res.status(200).send({
done: true,
message: "Login successful",
user,
authenticated: true,
sessionId: req.sessionID, // Mobile app should use this session ID
sessionCookie: sessionName, // Cookie name for mobile app
// Important: Mobile app must update its session cookie!
updateSessionRequired: oldSessionId !== req.sessionID
});
}); });
}); });
}); // Close login callback }); // Close login callback

View File

@@ -24,6 +24,10 @@ const sessionConfig = {
secure: isProduction(), // Required when sameSite is "none" secure: isProduction(), // Required when sameSite is "none"
domain: isProduction() ? ".worklenz.com" : undefined, domain: isProduction() ? ".worklenz.com" : undefined,
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
},
// Custom session ID handling for mobile apps
genid: () => {
return require('uid-safe').sync(24);
} }
}; };
@@ -32,4 +36,19 @@ console.log("Session configuration:", {
secret: "[REDACTED]" secret: "[REDACTED]"
}); });
export default session(sessionConfig); const sessionMiddleware = session(sessionConfig);
// Enhanced session middleware that supports both cookies and headers for mobile apps
export default (req: any, res: any, next: any) => {
// Check if mobile app is sending session ID via header (fallback for cookie issues)
const headerSessionId = req.headers['x-session-id'];
const headerSessionName = req.headers['x-session-name'];
if (headerSessionId && headerSessionName && !req.headers.cookie) {
console.log("Mobile app using header-based session:", headerSessionId);
// Inject the session cookie from header for session middleware to process
req.headers.cookie = `${headerSessionName}=s%3A${headerSessionId}`;
}
sessionMiddleware(req, res, next);
};