Sergio Xalambrí

Share session and cookies between Next and Remix

I have been migrating a Next.js app to Remix for a few months. I already wrote how to run them together in the same Express server.

The next thing I had to do was see how to share the authenticated user data between Next and Remix.

Share Cookies

The first thing is to share cookies. Luckily, they are running on the same server, so they share the domain, which means any request to both of them will come with the cookies. So we could read them and set them in both apps.

To simplify working with cookies what I did was to create a cookie object using Remix createCookie function, something like this:

export let sessionCookie = createCookie("session", {
 secrets: [requireEnv("COOKIE_SECRET", "s3cr3t")],
 httpOnly: true,
 sameSite: "lax",
 path: "/",
 secure: isProduction(),
 domain: requireEnv("COOKIE_DOMAIN", "localhost"),
 maxAge: 60 * 60 * 24, // 1 day
});

Now, I could import sessionCookie in Remix and use it as documented or in Next, and use it like this in API routes:

// src/pages/api/endpoint.ts
import { sessionCookie } from "~/cookies";

export default function handler(
 req: NextApiRequest,
 res: NextApiResponse
) {
 // more code

 // first I parse the cookie from the Cookie header
 let session = await sessionCookie.parse(req.headers.cookie)

 // more code

 // and to send it in the response I serialize it and set header
 res.setHeader("Set-Cookie", await sessionCookie.serialize(session));
 // more code
}

And I could even use it getServerSideProps.

// src/pages/something.tsx
import { sessionCookie } from "~/cookies";

export let getServerSideProps: GetServerSideProps = async ({ req }) => {
 // more code

 // first I parse the cookie from the Cookie header
 let session = await sessionCookie.parse(req.headers.cookie)

 // more code

 // and to send it in the response I serialize it and set header
 res.setHeader("Set-Cookie", await sessionCookie.serialize(session));

 // more code
}

As you can see, it's basically the same. We parse the cookie header, serialize the session, and set the Set-Cookie header.

Sessions

Sessions use cookies internally. Even if you don't store the session data in the cookie, you need a cookie to keep the session ID.

This means to create a session, we will use the cookie we made before

import { sessionCookie as cookie } from "~/cookies";

export let sessionStorage = createCookieSessionStorage({ cookie });

I also like to re-export parts of sessionStorage and create a wrapper of sessionStorage.getSession to receive a Request object.

export async function getSession(request: Request) {
 return await sessionStorage.getSession(request.headers.get("Cookie"));
}

export let { commitSession, destroySession } = sessionStorage;

But that getSession will work on Remix, not in Next, so I created a new wrapper called getToken since that's the only thing I store in the session anyway.

export async function getToken(request: NextPageContext["req"]) {
 let session = await sessionStorage.getSession(request.headers.cookie ?? "");
 return session.get("token") as string | null;
}

As you can see, getToken receives a Next.js request (it's using the NextPageContext type but also works with API routes requests).

Now, we can get the API token from the session in Next in a simpler way:

// src/pages/api/endpoint.ts
import { getToken } from "~/session";

export default function handler(
 req: NextApiRequest,
 res: NextApiResponse
) {
 let token = await getToken(req)

 // more code
}
// src/pages/something.tsx
import { sessionCookie } from "~/cookies";

export let getServerSideProps: GetServerSideProps = async ({ req }) => {
 let token = await getToken(req)
 // more code
}

I can use Remix cookies and sessions, which are really easy to work with within both Next and Remix.

Bonus: Authentication

Additionally, the first part we migrated was the authentication, using Remix Auth. It was straightforward to set up. It stored the API token automatically in the session. Then, I could use the getToken method in Next or auth.isAuthenicated from Remix Auth in the Remix app.