fix: change SameSite=Strict to SameSite=Lax for session and CSRF cookies (#46)
Safari's ITP blocks Strict cookies on certain navigations (direct URL entry, reverse proxy context), resulting in a 401 on login even with valid credentials. Lax is safe: CSRF attacks are prevented by the double-submit token and the HTTPS-only secure flag. Firefox and Chrome were unaffected.
This commit is contained in:
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.17.2] - 2026-04-13
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Auth: session cookie and CSRF cookie changed from `SameSite=Strict` to `SameSite=Lax` - Safari's ITP (Intelligent Tracking Prevention) was blocking `Strict` cookies on certain navigations (direct URL entry, reverse proxy), causing a 401 on login while other browsers worked fine (#46)
|
||||||
|
|
||||||
## [0.17.1] - 2026-04-13
|
## [0.17.1] - 2026-04-13
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "oikos",
|
"name": "oikos",
|
||||||
"version": "0.17.1",
|
"version": "0.17.2",
|
||||||
"description": "Self-hosted family planner - calendar, tasks, shopping, meal planning, budget and more. Private, open-source, no subscription.",
|
"description": "Self-hosted family planner - calendar, tasks, shopping, meal planning, budget and more. Private, open-source, no subscription.",
|
||||||
"main": "server/index.js",
|
"main": "server/index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
+5
-2
@@ -104,7 +104,10 @@ const sessionMiddleware = session({
|
|||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
// secure=true by default; set SESSION_SECURE=false in .env to allow HTTP (local dev without reverse proxy)
|
// secure=true by default; set SESSION_SECURE=false in .env to allow HTTP (local dev without reverse proxy)
|
||||||
secure: process.env.SESSION_SECURE !== 'false',
|
secure: process.env.SESSION_SECURE !== 'false',
|
||||||
sameSite: 'strict',
|
// lax (not strict): Safari ITP blocks strict cookies on certain navigations
|
||||||
|
// (e.g. reverse proxy, direct URL entry), causing 401 on login. Lax is safe
|
||||||
|
// because CSRF is protected by the double-submit token and HTTPS secure flag.
|
||||||
|
sameSite: 'lax',
|
||||||
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 Tage in ms
|
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 Tage in ms
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -193,7 +196,7 @@ router.post('/login', loginLimiter, async (req, res) => {
|
|||||||
// CSRF-Token als Cookie setzen (nicht httpOnly → lesbar für JS)
|
// CSRF-Token als Cookie setzen (nicht httpOnly → lesbar für JS)
|
||||||
res.cookie('csrf-token', req.session.csrfToken, {
|
res.cookie('csrf-token', req.session.csrfToken, {
|
||||||
httpOnly: false,
|
httpOnly: false,
|
||||||
sameSite: 'strict',
|
sameSite: 'lax',
|
||||||
secure: process.env.SESSION_SECURE !== 'false',
|
secure: process.env.SESSION_SECURE !== 'false',
|
||||||
maxAge: 1000 * 60 * 60 * 24 * 7,
|
maxAge: 1000 * 60 * 60 * 24 * 7,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ function csrfMiddleware(req, res, next) {
|
|||||||
req.session.csrfToken = generateToken();
|
req.session.csrfToken = generateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cookie bei jedem Request erneuern (SameSite=Strict, nicht httpOnly → JS-lesbar)
|
// Cookie bei jedem Request erneuern (SameSite=Lax, nicht httpOnly → JS-lesbar)
|
||||||
res.cookie('csrf-token', req.session.csrfToken, {
|
res.cookie('csrf-token', req.session.csrfToken, {
|
||||||
httpOnly: false,
|
httpOnly: false,
|
||||||
sameSite: 'strict',
|
sameSite: 'lax',
|
||||||
secure: process.env.SESSION_SECURE !== 'false',
|
secure: process.env.SESSION_SECURE !== 'false',
|
||||||
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 Tage (gleich wie Session)
|
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 Tage (gleich wie Session)
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user