fix: gate cookie secure flag on TRUST_PROXY not NODE_ENV
secure:true cookies are only sent by browsers over HTTPS connections. When NODE_ENV=production (always set in the Docker container) but no TLS proxy is in front, the browser receives the cookie on login but refuses to send it on subsequent HTTP requests — causing every authenticated endpoint (/stream, /status, etc.) to return 401. The correct signal is TRUST_PROXY: it is only set when a TLS-terminating reverse proxy is confirmed to be in front. Affects emby_user and csrf_token cookies across login, /csrf refresh, and logout.
This commit is contained in:
@@ -70,13 +70,15 @@ router.post('/login', loginLimiter, async (req, res) => {
|
||||
// Set authentication cookie (signed when COOKIE_SECRET is set).
|
||||
// rememberMe=true → persistent cookie, expires in 30 days
|
||||
// rememberMe=false → session cookie, expires when browser closes
|
||||
// secure is always true — the app should sit behind HTTPS in production;
|
||||
// behind a reverse proxy set TRUST_PROXY=1 so req.secure works correctly.
|
||||
// secure:true only when TRUST_PROXY is set — i.e. a TLS-terminating reverse
|
||||
// proxy is in front. Without it the app may be accessed over plain HTTP and
|
||||
// secure cookies would never be sent back by the browser.
|
||||
const cookiePayload = JSON.stringify({ id: user.Id, name: user.Name, isAdmin });
|
||||
const signed = !!process.env.COOKIE_SECRET;
|
||||
const secureCookie = !!process.env.TRUST_PROXY; // only send over HTTPS when behind a TLS proxy
|
||||
const cookieOptions = {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
secure: secureCookie,
|
||||
sameSite: 'strict',
|
||||
signed,
|
||||
path: '/'
|
||||
@@ -91,7 +93,7 @@ router.post('/login', loginLimiter, async (req, res) => {
|
||||
const csrfToken = crypto.randomBytes(32).toString('hex');
|
||||
res.cookie('csrf_token', csrfToken, {
|
||||
httpOnly: false, // intentionally readable by JS for the double-submit pattern
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
secure: secureCookie,
|
||||
sameSite: 'strict',
|
||||
path: '/'
|
||||
});
|
||||
@@ -142,7 +144,7 @@ router.get('/csrf', (req, res) => {
|
||||
const csrfToken = crypto.randomBytes(32).toString('hex');
|
||||
res.cookie('csrf_token', csrfToken, {
|
||||
httpOnly: false,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
secure: !!process.env.TRUST_PROXY,
|
||||
sameSite: 'strict',
|
||||
path: '/'
|
||||
});
|
||||
@@ -168,14 +170,14 @@ router.post('/logout', async (req, res) => {
|
||||
}
|
||||
res.clearCookie('emby_user', {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
secure: !!process.env.TRUST_PROXY,
|
||||
sameSite: 'strict',
|
||||
signed: !!process.env.COOKIE_SECRET,
|
||||
path: '/'
|
||||
});
|
||||
res.clearCookie('csrf_token', {
|
||||
httpOnly: false,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
secure: !!process.env.TRUST_PROXY,
|
||||
sameSite: 'strict',
|
||||
path: '/'
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user