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:
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user