CookieManager, SessionManager #5633
Replies: 2 comments 1 reply
-
Things like this will be much easier to implement once Remix adds support for Middleware. remix-run/react-router#9564 |
Beta Was this translation helpful? Give feedback.
-
We have an app where we've implemented something like this, as we had issues with sessions not always being committed: // server.js
const {
createRemixRequest,
sendRemixResponse,
} = require("@remix-run/express/dist/server");
function createRequestHandlerWithSessionManagement({
build,
getLoadContext,
mode = process.env.NODE_ENV,
}) {
const handleRequest = createRemixRequestHandler(build, mode);
return async (req, res, next) => {
try {
const request = createRemixRequest(req, res);
const loadContext = getLoadContext(req, res);
const initialData = structuredClone((await loadContext.session).data);
const response = /** @type Response */ (
await handleRequest(request, loadContext)
);
const session = await loadContext.session;
const hasSessionDataChanged = !deepEqual(session.data, initialData);
if (hasSessionDataChanged) {
response.headers.append(
"set-cookie",
await sessionStorage.commitSession(session)
);
}
await sendRemixResponse(res, response);
} catch (error) {
// Express doesn't support async functions, so we have to pass along the
// error manually using next().
next(error);
}
};
} getLoadContext(req) {
return {
session: sessionStorage.getSession(req.headers.cookie),
};
}, You can Overall very much in favour of better session management, as manually managing it has proven to be a great way to blow your feet of by means of session leaks as there's always a place a commit was missed. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Background
Remix's APIs for cookies and sessions work great, but they're very low-level. A common pattern for managing sessions (from the official docs) is
This is an excellent low-level API based on web fundamentals.
But competing frameworks like Rails and Astro have much more automatic cookie-management.
Each Astro route (their
loader/action
) receive acookies
object. When the application sets, appends, or deletes a cookie, Astro automatically setsset-cookie
headers on the response. See, e.g. https://github.com/withastro/astro/blob/6b156dd3b467884839a571c53114aadf26fa4b0b/packages/astro/src/core/cookies/cookies.ts#L71-L89A Rails session is similar. Rails tracks whether the session object is dirty and writes a
set-cookie
header for it if and only if the controller (loader/action) modified it. See, e.g. https://github.com/rails/rails/blob/e78ed07e008676752b2ed2cff97e74b31ffacaf5/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb#L106For both cookies and cookie-based sessions, the dirty tracking is extremely important! Imagine an action like
If simply loading the session were to set a
set-cookie
on the response, thenGET /login
would become uncacheable at the HTTP layer, dramatically hurting performance.Problem
Application authors have to include
in every response where they might have modified a session. That's fine for something like a
POST /login
route, where the session-management is right there in the loader. But imagine aPUT /widgets/$id
route that wants to write a success message to flash. It may not be obvious that writing to flash (or even reading from it!) requires serializing the session and writing aset-cookie
header.So the current APIs (a) force applications to duplicate boilerplate and (b) invite errors when applications try to abstract the boilerplate away.
Proposal
Either in core or as one or two officially-supported addons, support higher-level cookies and session APIs.
cookies
object to the loader that is a proxy forrequest.cookies
with dirty-trackingResponse
(afterloader/action
returns), Remix writes any added, appended, or deleted cookiessession
with dirty-trackingResponse
, Remix commits the session and adds it as aset-cookie
header if it was modifiedBeta Was this translation helpful? Give feedback.
All reactions