Setup
Backend: Express.js, express-session, connect-mongo, cors, modules working in Node.js host from Heroku (Free edition), and storing data to MongoDB Atlas (cloud-based Mongo solution)
Frontend: React.js, axios, working in Godaddy shared linux host.
I use the Heroku free domain (https://app-name.herokuapp.com), and a bought domain for Godaddy.
Also, for free HTTPS Certificate, i use Cloudflare (Free edition).
The problem
The communication between frontend and backend works well. Data is sent and is received. But, in the login system i need to implement, the data is sent, passes the database check correctly, and after it, i save the session to the database. It works well, until THE COOKIE SETTING PART, WHEN I DON'T RECEIVE THE SESSION COOKIE IN THE FRONTEND DOMAIN.
Code
app.js
// In my app.js, the entry point for backend
// ---> This line is just after module importing.
dotenv.config();
const storage = new store({
mongoUrl: ""+process.env.MONGODB_URI, collectionName: "sessions", ttl: 100, autoRemove: "native"
});
app.disable("X-Powered-By");
app.use(cors({origin: "https://my.godaddy.subdomain", credentials: true, methods: "GET, POST, PUT, DELETE"}));
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Origin", "https://my.godaddy.subdomain");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-HTTP-Method-Override");
res.header("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
next();
});
// "my.godaddy.subdomain" is the SUBDOMAIN where i have an Administrators' login page, so it is separated from public site "godaddy.subdomain" (ONLY FOR EXAMPLE PURPOSE)
app.use(express.json());
app.use(express.urlencoded({extended: false}));
mongo.connect(""+process.env.MONGODB_URI,
{
useNewUrlParser: true,
useUnifiedTopology: true,
dbName: "Test_DB"
}
).then(() => console.log("Connected to MongoDB!"))
.catch((err) => console.log("Error connecting to MongoDB: "+err));
app.use(session({
name: "admin_session",
secret: ""+process.env.SERVER_SECRET,
resave: true,
rolling: false,
saveUninitialized: false,
unset: "destroy",
cookie: {
sameSite: "none", // I tried changing this a thousand times, no result...
secure: true, // The maximum i could was set a session sucessfully IN THE HEROKU
httpOnly: true, // BACKEND (no cross-domain), but that would be useless...
maxAge: 8600000
},
store: storage
}));
// ---> After this line, the routing code, all working fine.
admin_routing.js
// The Admin route, called admin_routing.js, used in app.js
router.route("/admin/login").post(async (req, res, next) =>
{
const {username, password} = req.body;
const admin = await Admin.find({user_login: username}).then((doc) => doc.pop());
if(admin.user_login === username)
{
await bcrypt.compare(password, admin.user_pass).then((same) =>
{
if(same)
{
req.session.adminID = admin._id;
req.session.save((err) => console.log(err)); // here i save the session
console.log(req.body, req.session); // it is sucessfully saved but
res.send({error: "Sucess!"}); // NO COOKIE IS SENT...
}
else
{
res.send({error: "Check your credentials and try again."});
}
});
}
else
{
res.send({error: "No administrators found."});
}
});
Frontend request (Login component)
// The part of my frontend where i post login data, in a React.js Component
await axios.post("https://my-app.herokuapp.com/admin/login",
{username: Inputs[0].value, password: Inputs[1].value}, {withCredentials: true, method: "POST",
headers: {'Access-Control-Allow-Origin': 'https://my-app.herokuapp.com'}})
.then((res) =>
{
document.getElementById("err-bc").innerText = ""+res.data.error; // Design purpose
document.getElementById("err-bc").style.visibility = "visible";
console.log(res.data);
}).catch((err) =>
{
document.getElementById("err-bc").innerText = ""+res.data.error; // Design purpose
document.getElementById("err-bc").style.visibility = "visible";
});
How it should work when fixed
It must save the session, send a cookie back to my frontend in my subdomain, and when the logged in ADMIN user goes to public pages it must still keep the cookie for authentication. So adm.mydomain.com receives the authentication cookie, and keeps it when the user goes to mydomain.com AND www.mydomain.com (public pages).
Hope someone have the answer, now i've been trying to solve for two days.
Thanks.