The cookie doesn't allow response on production environment
phivh opened this issue · comments
The scenario is when the backend service based Koajs and Koa-session with the default configuration:
app.keys = [process.env.SESSION_SECRET];
const isProd = process.env.NODE_ENV === 'production' ? true : false;
const SESSION_CONFIG: any = {
key: 'koa:sess',
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
overwrite: true,
httpOnly: isProd,
signed: true,
rolling: true,
renew: false,
secure: isProd,
sameSite: 'None',
};
When the request calling to the endpoint and get an error code 500, it doesn't respond as expected and set the cookie to the browser.
But when removing secure
and sameSite
, it's working but the cookie doesn't set to the browser.
I believe there are a couple of things you should consider to fix this issue. Do you intentionally want the cookie sent in a third-party context? If so you are correct to set the sameSite
property to none, however, modern browsers will only set cookies that are marked with sameSite=none
if they are also marked with secure. This could be one reason why your cookie is not being set in development when NODE_ENV
does not equal production.
My best guess in why you are receiving an HTTP status code of 500 is koa-session is throwing the error Cannot send secure cookie over unencrypted connection
.
To hopefully get this fixed can you provide more info about the environment you are using, are you testing locally on your development machine or on a live production server? Are you using HTTP or HTTPS requests?
I believe there are a couple of things you should consider to fix this issue. Do you intentionally want the cookie sent in a third-party context? If so you are correct to set the
sameSite
property to none, however, modern browsers will only set cookies that are marked withsameSite=none
if they are also marked with secure. This could be one reason why your cookie is not being set in development whenNODE_ENV
does not equal production.My best guess in why you are receiving an HTTP status code of 500 is koa-session is throwing the error
Cannot send secure cookie over unencrypted connection
.To hopefully get this fixed can you provide more info about the environment you are using, are you testing locally on your development machine or on a live production server? Are you using HTTP or HTTPS requests?
Thanks for your answer.
I've tested under the local machine and it seems working and I mean here on the live production when
NODE_ENV
equal to production
as you can see my code here:
const isProd = process.env.NODE_ENV === 'production' ? true : false;
Under local development with the output:
const SESSION_CONFIG: any = {
...
httpOnly: false,
signed: true,
rolling: true,
renew: false,
secure: false,
sameSite: 'None',
};
On live production with the output:
const SESSION_CONFIG: any = {
...
httpOnly: true,
signed: true,
rolling: true,
renew: true,
secure: true,
sameSite: 'None',
};
And of course on live production with SSL request
I am going to assume you are running your application behind a proxy in production. Adding app.proxy = true
should sort this issue out. The reason why you are having this issue is because the proxy is sending an HTTP request to the application and not the SSL HTTPS request, setting app.proxy = true
tells Koa that when determining whether a request is secure it may trust the headers that the load-balancer or proxy adds to each request.
I have tested this solution on a local development machine and production server using Google Cloud Run (uses a reverse proxy) and had success with this simple test application:
'use strict'
const Koa = require('koa')
const session = require('koa-session')
const app = new Koa()
const isProd = process.env.NODE_ENV === 'production' ? true : false
const PORT = process.env.PORT || 3000
app.keys = [process.env.SESSION_SECRET]
app.proxy = true
const SESSION_CONFIG = {
key: 'koa:sess',
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
overwrite: true,
httpOnly: isProd,
signed: true,
rolling: true,
renew: false,
secure: isProd,
sameSite: 'none'
}
app.use(session(SESSION_CONFIG, app))
app.use(ctx => {
let views = ctx.session.views || 0
ctx.session.views = ++views
ctx.body = `${views} views`
})
app.listen(PORT)
Hope this helps 😄
Thanks for your solution, it seems the server allow when set proxy=true
but the response with the cookie doesn't set to browser.
My origin request from requestdomain.com
to api.domain.com
and the server set a cookie to api.domain.com
, not to the requestdomain.com
. Although, sameSite=None
I am not sure if this stackoverflow answer could help you here. You would have to use ctx.cookies.set('domain', 'api.domain.com')
. This gives me these cookies when adding this to the example I used above:
Thanks @dominicegginton , The solution above was helpful and we also can set domain: 'api.domain.com'
in the configuration. Maybe this is also a session to learn.
const SESSION_CONFIG = { key: 'koa:sess', maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days overwrite: true, httpOnly: isProd, signed: true, rolling: true, renew: false, secure: isProd, sameSite: 'None', domain: 'api.anotherdomain.com', }
Thanks for your help!
No problem I am happy to help, your soultion of setting the domain
value within the koa-session config I belive is a better way than the one I suggested, I will add this to the documentation when I have time.
Thanks all, I already fixed the issue.
I'll re-format the answer of @phivh to make it more readable
const isProd = process.env.NODE_ENV === 'production' ? true : false
const CONFIG = {
key: 'koa.sess',
maxAge: 86400000,
autoCommit: true,
overwrite: true,
httpOnly: isProd,
signed: true,
rolling: false,
renew: false,
secure: isProd,
sameSite: 'None',
};
app.use(koaSession(CONFIG, app));