Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing variables from middleware to page in Next.js 12 new middleware api

Tags:

next.js

Background to the Question

Vercel recently released their biggest update ever to Next.js. Next.js blog. They introduced a lot of new features but my favorite is Middleware which:

"enables you to use code over configuration. This gives you full flexibility in Next.js because you can run code before a request is completed. Based on the user's incoming request, you can modify the response by rewriting, redirecting, adding headers, or even streaming HTML."

The Question

The following structure is used in this question.

- /pages
    index.js
    signin.js
    - /app
      _middleware.js # Will run before everything inside /app folder
      index.js

The two important files here are /app/_middleware.js and /app/index.js.

// /app/_middleware.js

import { NextResponse } from 'next/server';

export function middleware(req, event) {
  const res = { isSignedIn: true, session: { firstName: 'something', lastName: 'else' } }; // This "simulates" a response from an auth provider
  if (res.isSignedIn) {

    // Continue to /app/index.js
    return NextResponse.next();
  } else {

    // Redirect user
    return NextResponse.redirect('/signin');
  }
}
// /app/index.js

export default function Home() {
  return (
    <div>
      <h1>Authenticated!</h1>
      
      // session.firstName needs to be passed to this file from middleware
      <p>Hello, { session.firstName }</p>
    </div>
  );
}

In this example /app/index.js needs access to the res.session JSON data. Is it possible to pass it in the NextResponse.next() function or do you need to do something else?

In express you can do res.locals.session = res.session

like image 203
Gnusson Avatar asked Nov 14 '22 18:11

Gnusson


2 Answers

According to the examples (look specifically at /pages/_middleware.ts and /lib/auth.ts) it looks like the canonical way to do this would be to set your authentication via a cookie.

In your middleware function, that would look like:

// /app/_middleware.js

import { NextResponse } from 'next/server';

export function middleware(req, event) {
  const res = { isSignedIn: true, session: { firstName: 'something', lastName: 'else' } }; // This "simulates" a response from an auth provider
  if (res.isSignedIn) {

    // Continue to /app/index.js
    return NextResponse.next().cookie("cookie_key", "cookie_value"); // <--- SET COOKIE
  } else {

    // Redirect user
    return NextResponse.redirect('/signin');
  }
}
like image 177
Ben Avatar answered Mar 15 '23 22:03

Ben


Only weird solution is to inject your custom object into req.body because next.js v12 middleware doesn't allow altering the NextApiRequest

export const middleware = async (req: NextApiRequest) => {
  //   return new Response("Hello, world!");
  req.body = { ...req.body, foo: "bar" };
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  await middleware(req);
  // now req.body.foo=='bar'
}

They do however explain how you can extend middleware here, but the example given (copied below) isn't meaningful enough because it doesnt show how withFoo() is implemented

import { NextApiRequest, NextApiResponse } from 'next'
import { withFoo } from 'external-lib-foo'

type NextApiRequestWithFoo = NextApiRequest & {
  foo: (bar: string) => void
}

const handler = (req: NextApiRequestWithFoo, res: NextApiResponse) => {
  req.foo('bar') // we can now use `req.foo` without type errors
  res.end('ok')
}

export default withFoo(handler)

I assumed based on the above, withFoo.ts should be like this. But still wasn't successful in accessing request.Foo()

import { NextApiHandler, NextApiRequest } from "next";


export const withFoo = (handler: NextApiHandler) => {
  //do stuff

};

Maybe someone can chip in?

like image 37
Korayem Avatar answered Mar 15 '23 23:03

Korayem