I got struggle when I deploy my backend with EC2 and the domain after deploy is http://52.xx.xx.xx:8080. I can not set cookies for request header. The flow is that When the user clicks on "Login" on the frontend (localhost:5173), they are redirected to the SSO server (http://localhost:8080/login?serviceURL=localhost:5173) to log in.
When the user enters their email and password, Passport saves the session (sessionId) of the SSO server into the database's Sessions table and sets a cookie (containing the sessionId).
The client then sends a request to the SSO server with the SSO token (along with the cookies). At this point, the server retrieves the cookie (sessionId), queries the database using the sessionId, and populates req.user (via deserializeUser).
However, when I publish the SSO server on EC2 with the domain 52.xx.xx.xx, the connect.sid cookie in the browser has the domain 52.xx.xx.xx. However, I am unable to set the cookie in the headers for the frontend to call the API at http://52.xx.xx.xx:8080/verify-token and req.user will be undefined so it will response 404 "Not match sso token". The imgages depict that it works fine for localhost:8080. config.session file
app.use(
session({
secret: "keyboard cat",
store: myStore,
resave: false, // we support the touch method so per the express-session docs this should be set to false
proxy: true, // if you do SSL outside of node.
saveUninitialized: false,
checkExpirationInterval: 15 * 60 * 1000, // The interval at which to cleanup expired sessions in milliseconds.
expiration: 500 * 1000,
cookie: {
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000,
secure: false,
path: "/",
},
})
);
// continue as normal
myStore.sync();
app.use(passport.authenticate("session"));
passport.serializeUser(function (user, cb) {
process.nextTick(function () {
// cb(null, { id: user.id, username: user.username });
cb(null, user);
});
});
passport.deserializeUser(function (user, cb) {
process.nextTick(function () {
return cb(null, user);
});
});
};
loginController.js
const getLoginPage = (req, res) => {
const { serviceURL } = req.query;
return res.render("login.ejs", {
redirectURL: serviceURL,
});
};
const verifySSOToken = async (req, res) => {
try {
const { ssoToken } = req.body;
console.log("check code from req.user", req.user);
if (req.user && req.user.code && req.user.code === ssoToken) {
const refreshToken = uuidv4();
//update user refresh token
await AuthService.updateRefreshToken(req.user.email, refreshToken);
let payload = {
user_id: req.user.user_id,
roleWithPermission: req.user.roleWithPermission,
first_name: req.user.first_name,
last_name: req.user.last_name,
phone: req.user.phone,
address: req.user.address,
email: req.user.email,
};
let token = createToken(payload);
//set cookies
res.cookie("refresh_token", refreshToken, {
httpOnly: true,
maxAge: 60 * 60 * 24 * 1000,
secure: false,
path: "/",
});
res.cookie("access_token", token, {
httpOnly: true,
maxAge: 60 * 60 * 1000,
secure: false,
path: "/",
});
const resData = {
user_id: req.user.user_id,
access_token: token,
refresh_token: refreshToken,
email: req.user.email,
first_name: req.user.first_name,
last_name: req.user.last_name,
phone: req.user.phone,
address: req.user.address,
roleWithPermission: req.user.roleWithPermission,
};
//destroy session
req.session.destroy(function (err) {
req.logout();
});
return new OK({
EM: "Verify token successfully",
DT: resData,
}).send(res);
} else {
throw new UnauthorizedResponse({
EM: "Not match sso token",
DT: "",
});
}
} catch (error) {
console.log(error);
if (error instanceof ErrorResponse) {
return error.send(res);
}
return new ErrorResponse({
EM: "Error verifying SSO token from server",
}).send(res);
}
};
passportController.js
import passport from "passport";
import LocalStrategy from "passport-local";
import AuthService from "../services/auth.service";
const configPassport = () => {
passport.use(
new LocalStrategy({}, async (username, password, done) => {
try {
const rawData = {
valueLogin: username,
password: password,
};
const user = await AuthService.login(rawData);
console.log("Check user passport Controller", user);
if (user && +user.EC === 1) {
return done(null, user.DT);
} else {
return done(null, false, { message: user.EM });
}
} catch (error) {
console.error("Login error:", error);
return done(error);
}
})
);
};
const handleLogout = (req, res) => {
// req.logout();
// res.redirect("/login");
req.session.destroy(function (err) {
req.logout();
res.redirect("/");
});
};
export { configPassport, handleLogout };
cors:
require("dotenv").config();
const allowedOrigins = [
"*",
process.env.REACT_PATH,
process.env.REACT_PATH_SSO, \\localhost:5173
process.env.SERVICE_PATH,
process.env.DOCKER_SSO_PATH,
process.env.DOCKER_SSO_PATH + "/api/v1",
"http://" + process.env.HOST_NAME + ":" + process.env.PORT, \\localhost:8080
process.env.PUBLIC_SSO_PATH, \\http://52.xx.xx.xx:8080
process.env.PUBLIC_SSO_PATH + "/api/v1",
process.env.PRIVATE_SSO_PATH,
process.env.PRIVATE_SSO_PATH + "/api/v1",
process.env.SERVICE_PATH,
].filter(Boolean);
module.exports = allowedOrigins;
import allowedOrigins from "./allowedOrigin";
const corsOption = {
origin: (origin, callback) => {
if (allowedOrigins.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allowedHeaders: [
"Content-Type",
"Authorization",
"X-Requested-With",
"Access-Control-Allow-Credentials",
],
exposedHeaders: [
"Set-Cookie",
"Access-Control-Allow-Credentials",
"set-cookie",
],
credentials: true,
optionsSuccessStatus: 200,
};
export default corsOption;
import allowedOrigins from "../configs/CORS/allowedOrigin";
const credentials = (req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.header("Access-Control-Allow-Credentials", true);
}
next();
};
export default credentials;
enter image description here enter image description here
I have tried to set sameSite to "lax" but it doesn't work. If you need more detail, please comment