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]
|
||||
|
||||
## [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
|
||||
|
||||
### Fixed
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"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.",
|
||||
"main": "server/index.js",
|
||||
"type": "module",
|
||||
|
||||
+5
-2
@@ -104,7 +104,10 @@ const sessionMiddleware = session({
|
||||
httpOnly: true,
|
||||
// secure=true by default; set SESSION_SECURE=false in .env to allow HTTP (local dev without reverse proxy)
|
||||
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
|
||||
},
|
||||
});
|
||||
@@ -193,7 +196,7 @@ router.post('/login', loginLimiter, async (req, res) => {
|
||||
// CSRF-Token als Cookie setzen (nicht httpOnly → lesbar für JS)
|
||||
res.cookie('csrf-token', req.session.csrfToken, {
|
||||
httpOnly: false,
|
||||
sameSite: 'strict',
|
||||
sameSite: 'lax',
|
||||
secure: process.env.SESSION_SECURE !== 'false',
|
||||
maxAge: 1000 * 60 * 60 * 24 * 7,
|
||||
});
|
||||
|
||||
@@ -33,10 +33,10 @@ function csrfMiddleware(req, res, next) {
|
||||
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, {
|
||||
httpOnly: false,
|
||||
sameSite: 'strict',
|
||||
sameSite: 'lax',
|
||||
secure: process.env.SESSION_SECURE !== 'false',
|
||||
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 Tage (gleich wie Session)
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user