Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Does Iron-session work with Next App Router? #594

Closed
chrisroode opened this issue May 29, 2023 · 16 comments
Closed

Question: Does Iron-session work with Next App Router? #594

chrisroode opened this issue May 29, 2023 · 16 comments

Comments

@chrisroode
Copy link

I noticed that all the iron-session examples use the pages router for api routes. Tried some experimenting getting the api requests into the app router instead of pages router. Is this possible, or does it need to be a new feature added?

BTW, I love the library so far, and I would love to help if needed.

@gerardnico
Copy link

Not yet finalized still in beta, check
I'm going to use JWT with Jose. Less lock-in and you can read the session data in the browser.

@netgfx
Copy link

netgfx commented Jun 19, 2023

Could this be the reason I'm getting:

Error: No router instance found.
You should only use "next/router" on the client side of your app.

when trying to apply the redirection from useUser (following the iron-session nextjs example)

I'm using Nextjs 13

@gerardnico
Copy link

@netgfx Next 13 has the notion of server and client components.
By default, the components are server components running only on NodeJs until you specify that they are clients with useClient.
next-router is a client component as this is routing in the browser.
Check this document

@netgfx
Copy link

netgfx commented Jun 21, 2023

it was actually the wrong import of next/router instead of the next/navigation which now also exists in NextJS. It was quite easy to miss when setting everything up. The migration documentation helped out though.

@renchris
Copy link
Contributor

How would I migrate using serversideprops and withIronSessionSsr in nextjs pages router to nextjs app router?

@pdiazdumont
Copy link

I recently migrated an application to the app router, the withIronSessionSsr method is just a wrapper for easier use, to achieve the same functionality you can just leverage the low level seal/unseal methods. Something like this (in a server component):

import { unsealData } from 'iron-session/edge';
import { cookies } from 'next/headers';

export default async function Page() {
  const cookieStore = cookies();

  const encryptedSession = cookieStore.get('name-of-your-cookie')?.value;

  const session = encryptedSession
    ? await unsealData(encryptedSession, {
        password: 'your-password',
      })
    : null;

  return <div>{session ? session.some_value : 'not authenticated'}</div>;
}

Creating the session can be tricky since you need to set the encrypted session with a cookie header either in a route handler or a middleware.

import { sealData } from 'iron-session/edge';

// endpoint to log in a user
export async function POST() {
  const session = JSON.stringify({
    userId: 1,
    name: 'john doe',
  });

  const encryptedSession = sealData(session, {
    password: 'your-password',
  });

  return new Response('ok', {
    status: 200,
    headers: { 'Set-Cookie': `name-of-your-cookie=${encryptedSession}` },
  });
}

@renchris
Copy link
Contributor

@pdiazdumont

What do you do with your returned Response with the headers cookies from your second code snippet of the API route handler? How do you get the encrypted session cookies in the returned response to the client cookie store that you then access in the first code snippet?

@pdiazdumont
Copy link

What do you do with your returned Response with the headers cookies from your second code snippet of the API route handler?

The route handler execution finishes, and the browser receives the response, it notices it has a Set-Cookie header and creates the cookie using the name and value defined in the header. After this is done the browser automatically includes the cookies when making requests.

How do you get the encrypted session cookies in the returned response to the client cookie store that you then access in the first code snippet?

The browser attaches the cookies to the request meaning that you can access that information when processing it. In Next.js case, it receives the request (with the session cookie included) and automatically provides different ways to read the value, for example the cookies method inside the component or the request.cookies.get('cookie-name') in a middleware. It's up to you to decide what to do that information, the iron session methods (withIronSessionApiRoute, withIronSessionSsr) did the work of reading the value, decrypting it, and making it available in the request object but since that is not supported yet you need to do it by yourself (as shown in my first snippet).

Hope it helps, it's a good idea to review how cookies work in general.

@renchris
Copy link
Contributor

I expect the cookies to be assigned to the cookie storage on the client-side browser (which you can see by Inspecting page, going to the Application tab, and looking under the cookies tab) automatically once a Response with the appropriate set cookie headers is returned

I cannot get this to work with my server actions.

However, when I turn off server actions by removing the experimental server action flag in my config and removing the 'use server' tag in the file of my function where I call the API route handler, it works.

How did you get it to work with server actions? Or are you not using server actions?

@scottroot
Copy link

It is working just fine for us using it in the app dir with api routes.

Followed info here: #586
Had to upgrade to "iron-session": "8.0.0-alpha.0", and have to use a createResponse function as described in that other issue I linked.

@khentonx
Copy link

how would I handle the cookie "name-of-your-cookie" providing a value of [object promise] ?

@Archivedent1
Copy link

how would I handle the cookie "name-of-your-cookie" providing a value of [object promise] ?

Likely you didn't await the promise when retrieving the value to be set in the cookie.

@Archivedent1
Copy link

Requests and responses used in getIronSession are only used to set and get cookies, I think it makes sense to provide callback options that accept a cookie setter and getter instead of request and response, since it's always easy for user to create a custom instance that uses request and response for cookie operations anyways. At the same time since this is a small utility library I think it's not too difficult to fork and replace the usages of req and res in the getIronSession function to directly use Next's cookies() or some other mechanism, since these operations are stateless and server-side (Route Handlers, Server Actions, Server Components) that should cover most cases.

Just some personal insights, but I do always prefer a thoroughly tested and used codebase and not reinventing. So I think this functionality is better implemented in the main repo. Adding optional callbacks to be used isn't breaking and provides better flexability for rsc

@renchris
Copy link
Contributor

Hey everyone 👋

I have Iron Session now fully working with support for NextJS App Router and Server Actions.

The feature update is provided with documentation and a working example application. Please refer to my comment under the Roadmap v8 issue thread for it, being available as a pull request.

I would love your support in getting this PR approved so that we can complete the V8 branch to be pushed into the main branch to have Iron Session with App Router available for everyone to use.

@r3wt
Copy link

r3wt commented Sep 10, 2023

you can use cookies() from next/headers in a Server Component and unsealData() from iron-session

import {cookies} from 'next/headers';
import { unsealData } from 'iron-session';
import { AuthContextProvider } from "~/components/AuthProvider";

export default async function RootLayout({
  // Layouts must accept a children prop.
  // This will be populated with nested layouts or pages
  children,
}: {
  children: React.ReactNode,
}) {
  
  let session:SessionPayload|undefined = undefined;
  if(cookies().has('sid')){
    const sid = cookies().get('sid');
    if(sid!==undefined && process.env.COOKIE_SECRET ){
      const unsealed = await unsealData<{ session: SessionPayload }>(sid.value,{ password: process.env.COOKIE_SECRET });
      session = unsealed.session;
    }
  }

  return (
    <html lang="en">
      <body>
        <AuthContextProvider session={session}>
          {children}
        </AuthContextProvider>
      </body>
    </html>
  )
}

@vvo
Copy link
Owner

vvo commented Nov 20, 2023

Hey there, iron-session v8 is live now 👍 https://github.com/vvo/iron-session and compatible with app router. We even have demos: https://get-iron-session.vercel.app/

Good luck.

@vvo vvo closed this as completed Nov 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants