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 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
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');
}
}
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With