I am a newbie in web development, I developed my first basic CRUD app. It works as expected in my local. As a portfolio item, I wanted create an actual website. I bought domain name & SSL certificate etc, deployed my back end and front end etc. However I am struggling with an issue for the last couple of days. Please see the details below
Background Info
Server: I have a nodejs application on Heroku (example.com). I bought an ssl certificate for my domain (i.e. example.com). I inserted certificate and intermediate certificate in Heroku and linked with my back end.
Client: I deployed my React & nextjs frontend on Vercel (subdomain.example.com). Vercel is creating its own certificate for subdomain.example.com
My issue is that I am receiving the following error in my website. After I wait couple minutes and refresh the error disappears. If I don't use it for some time again, the error reappears.
[Network] FetchError: request to https://example.com/graphql failed, reason: write EPROTO 139801265354624:error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1544:SSL alert number 80
See below my code for nodejs
const conn = await createConnection({
type: "postgres",
url: process.env.DATABASE_URL,
host: process.env.PG_HOST,
username: process.env.PG_USER,
password: process.env.PG_PASSWORD,
port: parseInt(process.env.PORT),
database: process.env.PG_DATABASE,
logging: true,
migrations: [path.join(__dirname, "./migrations/*")],
entities: [Bank, User, Report],
ssl: __prod__ ? {rejectUnauthorized: false} : false
})
const redisStore = connectRedis(session);
const redis = new Redis(process.env.REDIS_URL);
app.set("trust proxy", 1)
app.use(cors({
origin: __prod__ ? process.env.CORS_ORIGIN : "http://localhost:3000",
credentials: true
}))
app.use(
session({
name: COOKIE_NAME,
store: new redisStore({
client: redis,
disableTouch: true
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10,
httpOnly: true,
sameSite: "none",
secure: __prod__,
domain: __prod__ ? process.env.DOMAIN : undefined
} as CookieOptions ,
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
resave: false
})
)
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [BankResolver, UserResolver, ReportResolver],
validate: false
}),
context: ({req, res}): MyContext => ({req, res, redis})
})
await apolloServer.start()
apolloServer.applyMiddleware({app, cors: false});
app.listen(parseInt(process.env.PORT), () => console.log("Server listening on port 4000"));
}
Related
I am following Ben Awad full stack tutorial with same stack (
React
TypeScript
GraphQL
URQL/Apollo
Node.js
PostgreSQL
MikroORM/TypeORM
Redis
Next.js
TypeGraphQL
Chakra
)
But newer versions (the video was 2 years old), in 2:59:59, according to the video, when we make a register request through browser(client side) the qid cookies was supposed to get sent automatically but it doesn't work for me. Things work fine when I make request through my server (localhost port 5000, redirect to https://studio.apollographql.com/sandbox/explorer) but when it come to browser I successfullyy register the user but the cookies was not saved.
Here is the code I built in my server to set the cookies (redis connected):
app.use(
cors({
origin: ["http://localhost:3000", "https://studio.apollographql.com"],
credentials: true,
})
)
app.set("trust proxy", true);
app.use(
session({
name: "qid",
store: new RedisStore({ client: redisClient, disableTouch: true }),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, //10 years
httpOnly: false,
sameSite: "none",
secure: true, // cookie only works in https
},
saveUninitialized: false,
secret: "123456789",
resave: false,
})
);
Thanks guys and I appreciate you guys a lot.
I solved it: set sameSite: 'none' when you want to save cookie through sandbox and lax when you want to save it with browser.
I have a server that has its own domain and is using HTTPS. I have a website that has its own domain and is using HTTPS as well.
On the home page of the website, there is a login button and a sign up button. Both buttons lead to forms to execute their respective tasks, and both forms send requests to the server that respond with cookies, or at least that's what they are supposed to do.
I am using express-session in combination with Redis to store the session ids. Here is the config for that (connectToRedis is simply a function that returns a RedisClient):
const RedisStore = connectRedis(session);
const redisClient = await connectToRedis();
app.use(
session({
store: new RedisStore({
client: redisClient,
}),
cookie: {
httpOnly: true,
secure: true,
sameSite: "lax",
maxAge: TEN_YEARS,
},
resave: false,
saveUninitialized: false,
secret: SECRET,
name: AUTH_COOKIE,
})
);
For some reason the cookies are not being sent in the requests. The Set-Cookie header isn't even showing up! I tried changing SameSite to none (article), but that didn't work.
This is my first time deploying a production website, so all this HTTPS stuff is kind of new to me.
Thanks for your help, and if you need any extra information, please let me know.
IMPORTANT UPDATE:
Finally, I have made some progress (all it took was a pizza break).
I added the path key to my cookie config and gave it the value of /. I also set proxy to true.
So now it looks like this:
const RedisStore = connectRedis(session);
const redisClient = await connectToRedis();
app.use(
session({
store: new RedisStore({
client: redisClient,
}),
cookie: {
httpOnly: true,
secure: true,
sameSite: "none",
maxAge: TEN_YEARS,
path: "/",
},
resave: false,
saveUninitialized: false,
secret: SECRET,
name: AUTH_COOKIE,
proxy: true,
})
);
With this, the cookie is finally appearing in the requests, but it isn't being set in the browser...
I tried to see if my cookies is working ,so here's my code
const RedisStore = connectRedis(session)
const redisClient = redis.createClient()
app.use(
session({
//name: 'qid',
store: new RedisStore({ //ttl: how long it should last
client: redisClient,
//disableTTL :true, //make sure session last forever
//disableTouch: true, // make sure it does'nt have to update the last time it's ttl
}),
cookie:{
maxAge: 1000*60*60*24*365*10, //10 years
path: "/"
//httpOnly:true, //javascript front end can't access
//sameSite:'none', // csrf
//secure:false
//secure: __prod__ //cookie only works in https
},
saveUninitialized:true, //automatically create a empty session on default
secret: 'some secret', //env
resave: false,
})
)
app.listen(4000,()=>{
console.log('server stared on localhost:4000')
})
app.get('/products', (req,res,next) => {
console.log(req.session);
if(!req.session.userId){
req.session.userId = 1
}else{
req.session.userId = req.session.userId +1
}
console.log(req.session.userId) //test if work
res.send("hello")
})
So here's the thing, when I connect to localhost:4000/products, In the cookie session, I can only see these
But when I print out the results on vscode console, I can see the number is growing like below , so I do have a session, it's just not showing on the browser , can anyone tell me why is that?
server stared on localhost:4000
Session {
cookie: {
path: '/',
_expires: 2031-08-18T12:59:30.827Z,
originalMaxAge: 315360000000,
httpOnly: true
},
userId: 10
}
11
Session {
cookie: {
path: '/',
_expires: 2031-08-18T13:00:37.257Z,
originalMaxAge: 315360000000,
httpOnly: true
},
userId: 11
}
12
So I got a solution after a lot of tests, So if you only set your cookie to same-site:"none" without secure options ,it would be like my situation,but if you want to turn on secure option your endpoint have to be https, so I don't think this was the answer, and you can change to lax or other options it would act normal in your localhost,
Work in local host
lax
(don't set same site)
But due to secure policy https://www.chromium.org/updates/same-site you can't not pass cookie to some certain website (in my case I want to test cookies in my graphql apollo studio) without setting same-site:"none" secure, so I use mkcert to use https in my localhost
https://web.dev/how-to-use-local-https/ , and everything works,
Work
samesite : none
secure : true
https:yourendpoint
I've developed an app using React, Mongodb, Node, and Express and i'm using sessions for authentication. On the backend, I can successfully set a cookie a store a userID however when I try to make requests from the react app using axios, the userID session data is not sent.
This is my session config on the backend:
app.use(session({
name: SESS_NAME || "***",
secret: SESS_SECRET || "***",
saveUninitialized: false,
resave: false,
store: new MongoStore({
mongooseConnection: db,
collection: 'session',
ttl: parseInt(SESS_LIFETIME) / 1000 || (60 * 60 * 48) / 1000
}),
cookie: {
sameSite: true,
path: '/',
domain: APP_DOMAIN || 'localhost:4000',
secure: false, //NODE_ENV === 'production',
maxAge: parseInt(SESS_LIFETIME) || 60 * 60 * 48
}
}));
My cors is configured as follows:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:4000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Credentials", true);
next();
});
const corsConfig = {
origin:['http://localhost:3000', 'http://localhost:4000' ],
methods:['GET','POST'],
credentials: true,
};
app.use(cors(corsConfig));
after logging in I set the userID in my user Routes, which I confirmed is set by console logging:
req.session.userId = user._id;
This is an example request from my react app
axios.get('/user/auth', { withCredentials: true })
.then(response => {
...
Note that my app is being served on the same domain - I'm using the node app to serve the react app. my folder structure is similar to the following
- APP PARENT FOLDER
-CLIENT //Whole react app
-MODELS
-ROUTES
-SERVER.JS
-PACKAGE.JSON
-NODE_MODULES
I have searched everywhere and tried everything I can think of... no luck. I would appreciate any help!
I've already checked articles on stack overflow and tried to implement the fixes but have had no luck. I've tried the following fixes:
// in my index.js file
axios.defaults.withCredentials = true;
and adding
{ withCredentials: true }
to all of my requests
When I take the userid created at login (ex: 5d6b5d2b09f7d1332543ba90) and manually plug this into the user Route on the backend then everything works fine.
When I console log the session on every request made by the react app it looks like this:
Session {
cookie:
{ path: '/',
_expires: 2019-09-05T05:38:09.657Z,
originalMaxAge: 172800,
httpOnly: true,
sameSite: true,
domain: 'localhost:4000',
secure: false },
}
When it should look like this:
Session {
cookie:
{ path: '/',
_expires: 2019-09-05T05:38:09.657Z,
originalMaxAge: 172800,
httpOnly: true,
sameSite: true,
domain: 'localhost:4000',
secure: false },
userId: 5d6b5c2b03f7d5532543ba90 }
To make my webapp ready for production, I wanted to set the session cookie property "secure" from false to true.
The app is hosted by Aws and is built like this:
Route53 -> CloudFront -> ELB (no cluster, only SingleApp)
CloudFront is used to make the app accessible via SSL. The Nodejs app listens on an HTTP port.
Unfortunately the SessionCookie is not set.
If I set secure to false, the login works and the session cookie is set. So it only seems to depend on this property.
I also set "trust proxy" to true, but unfortunately without success.
Express.js:
const ExpressApp=express();
ExpressApp.set("trust proxy", (ip)=>{
return true;
});
...
session:
const expiryDate = new Date( Date.now() + 60 * 60 * 1000 ); // 1 hour
return session({
genid: (req) => {
return uuid() // use UUIDs for session IDs
},
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
proxy:true,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
rolling: true,
cookie:{
secure:true,
httpOnly:true,
expires: expiryDate
}
})
CloudFront:
https://pasteboard.co/Ib9mTED.png