This problem has been driving me mad. I am using React with Apollo (GraphQL) on the frontend and authenticating using passport.js and express cookie-session
on the backend. Everything works perfectly from any browser (haven't tested safari) on a desktop, however the cookie does not save on IOS and the user cannot login. This problem only happens using passport-local
and if the browser does not already have a cookie. If I login using passport-google
or passport-facebook
it works, then if I logout and use passport-local
again, it works, even if it's a different user. Also, it works the first time around if I go to my settings and turn off "Prevent Cross-Site Tracking" for IOS Safari, however I can't turn that off if I want to use this as a PWA.
My express setup looks like this (leaving out all the imports):
app.use(
cookieSession({
maxAge: 24 * 60 * 60 * 1000 * 30,
keys: [process.env.COOKIE_KEY],
overwrite: true
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
const whitelist = [
"https://toomanylists.com",
"https://www.toomanylists.com"
];
app.use(
cors({
origin: (origin, callback) => {
console.log(origin);
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error("blocked by CORS"));
}
},
credentials: true
})
);
app.options("*", cors());
app.use("/auth", authRoutes);
mongoose.connect(process.env.MONGODB_URI);
mongoose.connection.once("open", () => {
console.log("Connected to Database");
});
const authCheck = (req, res, next) => {
if (!req.user) {
res.redirect("https://toomanylists.com");
} else {
next();
}
};
app.use(
"/graphql",
authCheck,
graphqlHTTP({
schema: schema,
graphiql: true
})
);
My login route:
router.post("/login", jsonParser, (req, res, next) => {
passport.authenticate("user-login", (err, user, info) => {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).send(JSON.stringify(info));
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
return res.status(200).send(JSON.stringify(info));
});
})(req, res, next);
});
In React I am sending the request using fetch API:
fetch(<my_server_url/login>, {
method: "POST",
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(this.state)
}).then(response => {
//if fails alerts with custom message
if (response.status === 401) {
response.json().then(json => {
alert(json.message);
});
} //if successful refresh with cookies
if (response.status === 200) {
window.location.reload(false);
}
});
Another, maybe related, issue is that if I add {secure: true}
option to cookie-session
it doesn't work at all, even though I am using a valid SSL cert through AWS where the frontend is hosted in an S3 bucket. The backend is on heroku and also is https. The site is live if it helps for anyone to check it out and try using it and inspecting the dev tools. I haven't tested it on android or ipad yet. https://toomanylists.com
Anyway, I suppose this is a long shot but I am hoping maybe there is something easy I am missing and it is not an unsolvable IOS issue with my setup and them preventing cookies (is this new in IOS 12?). Also, does anyone know if this would also be an issue using JWT's and if that is a secure way to authenticate users?