Next.js migration guide v6 to v7
Overview
In this migration guide, we will go over the process of migrating from @frontegg/[email protected]
to @frontegg/[email protected]
. The new version introduces some breaking changes, please make sure to follow the below instructions carefully.
This guide is intended for applications that use SSR and withFronteggApp
. If you used FronteggProviderNoSSR
in your project, there is no need to update your project.
âš¡ Before you start: âš¡
Next.js
@frontegg/nextjs
supports up to Next.js version 13.2.4
Prerequisites:
Node >= 16
Next >= 12
Typescript >= 3.9.7The files in this guide are in typescript - if you are working in js, simply change the file types and remove the typing.
STEP 1: Frontegg API middleware migration
- Rename imports to
@frontegg/nextjs/middleware
. - Export Next.js config to mark as
externalResolver
and disable the response limit.
import { FronteggApiMiddleware } from '@frontegg/nextjs/middleware';
export default FronteggApiMiddleware;
export const config = {
api: {
externalResolver: true,
// https://nextjs.org/docs/messages/api-routes-response-size-limit
responseLimit: false,
},
};
export { fronteggMiddleware as default } from '@frontegg/nextjs';
STEP 2: Edge middleware migration
If you are using Next.js edge
middleware, (Ex: middleware.ts):
- Rename the imports to
@frontegg/nextjs/edge
. - Rename getSession to
getSessionOnEdge
. - Use the
redirectToLogin
method instead of building the login URL.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getSessionOnEdge, shouldByPassMiddleware, redirectToLogin } from '@frontegg/nextjs/edge';
export const middleware = async (request: NextRequest) => {
const pathname = request.nextUrl.pathname;
if (shouldByPassMiddleware(pathname)) {
return NextResponse.next();
}
const session = await getSessionOnEdge(request);
if (!session) {
return redirectToLogin(pathname);
}
return NextResponse.next();
};
export const config = {
matcher: '/(.*)',
};
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getSession, shouldByPassMiddleware } from '@frontegg/nextjs/edge';
export const middleware = async (request: NextRequest) => {
const pathname = request.nextUrl.pathname;
if (shouldByPassMiddleware(pathname /*, options: optional bypass configuration */)) {
return NextResponse.next();
}
const session = await getSession(request);
if (!session) {
// redirect unauthenticated user to /account/login page
const loginUrl = `/account/login?redirectUrl=${encodeURIComponent(pathname)}`;
return NextResponse.redirect(new URL(loginUrl, process.env['FRONTEGG_APP_URL']));
}
return NextResponse.next();
};
export const config = {
matcher: '/(.*)',
};
Pages Architecture Migration
import { withFronteggApp } from '@frontegg/nextjs';
function CustomApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}
export default withFronteggApp(CustomApp,
{
hostedLoginBox: true,
authOptions: {
// keepSessionAlive: true // Uncomment this in order to maintain the session alive
}
});
import { withFronteggApp } from '@frontegg/nextjs/pages';
function CustomApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}
export default withFronteggApp(CustomApp,
{
hostedLoginBox: true,
authOptions: {
// keepSessionAlive: true // Uncomment this in order to maintain the session alive
}
});
import { FronteggRouter, FronteggRouterProps } from '@frontegg/nextjs/pages';
export const getServerSideProps = FronteggRouterProps;
export default FronteggRouter;
export {
FronteggRouter as default,
FronteggRouterProps as getServerSideProps,
} from '@frontegg/nextjs';
Example page
import { useCallback } from "react";
import { GetServerSideProps } from "next";
import { getSession } from "@frontegg/nextjs/pages";
import { useAuth } from "@frontegg/nextjs";
import { useRouter } from "next/router"
export default function MyPage({ products }) {
const { user } = useAuth();
const router = useRouter();
const logout = useCallback(() => {
router.replace('/account/logout');
}, [router]);
return (
<div>
<h1>My Page</h1>
{products}
<div>
<img src={user?.profilePictureUrl} alt={user?.name} />
</div>
<div>
<span>Logged in as: {user?.name}</span>
</div>
<div>
<button onClick={logout}>Log out</button>
</div>
</div>
);
}
// In the `getServerSideProps` method you can get data from an external service to pull relevant data for a logged in user.
// we used the prop `products`. See the commented code for an example.
export const getServerSideProps: GetServerSideProps = withSSRSession(
async (context, session) => {
// const { data } = await fetch('{external}/product', {
// headers: {
// Authorization: 'bearer ' + session.accessToken,
// },
// });
return { props: {} };
}
);
import { GetServerSideProps } from 'next';
import { withSSRSession, useAuth } from '@frontegg/nextjs';
export default function MyPage({ products }) {
const {user} = useAuth();
//baseUrl should be your FRONTEGG_APP_URL from .env.local
const baseUrl = 'FRONTEGG_APP_URL'
const logout = () => {
window.location.href = `${baseUrl}/account/logout`;
};
return (
<div>
<h1>My Page</h1>
{products}
<div>
<img src={user?.profilePictureUrl} alt={user?.name}/>
</div>
<div>
<span>Logged in as: {user?.name}</span>
</div>
<div>
<button onClick={logout}>Log out</button>
</div>
</div>
);
}
// In the `getServerSideProps` method you can get data from an external service to pull relevant data for a logged in user.
// we used the prop `products`. See the commented code for an example.
export const getServerSideProps: GetServerSideProps = withSSRSession(
async (context, session) => {
// const { data } = await fetch('{external}/product', {
// headers: {
// Authorization: 'bearer ' + session.accessToken,
// },
// });
return { props: { } };
}
);
App Directory Architecture Aigration
- Rename imports from
@frontegg/nextjs/server
to@frontegg/nextjs/app
. - Move
FronteggAppProvider
to inside RootLayout :
import { FronteggAppProvider } from '@frontegg/nextjs/app';
export default function RootLayout({ children }: { children: React.ReactNode }) {
const authOptions = {
// keepSessionAlive: true // Uncomment this in order to maintain the session alive
}
return (
<html>
<head></head>
<body>
{/* @ts-expect-error Server Component for more details visit: https://github.com/vercel/next.js/issues/42292 */}
<FronteggAppProvider authOptions={authOptions} hostedLoginBox={false}>
{children}
</FronteggAppProvider>
</body>
</html>
);
}
import { FronteggAppProvider } from "@frontegg/nextjs/server";
export default function RootLayout({children}: {children: React.ReactNode;}) {
const authOptions = {
// keepSessionAlive: true // Uncomment this in order to maintain the session alive
}
return (
<FronteggAppProvider authOptions={authOptions} hostedLoginBox={true}>
<html>
<head></head>
<body>{children}</body>
</html>
</FronteggAppProvider>
);
}
import { FronteggAppRouter } from '@frontegg/nextjs/app';
export default FronteggAppRouter;
export { FronteggAppRouter as default } from '@frontegg/nextjs/client';
Rename getSession
and getUserTokens
to getAppUserSession
and getAppUserToken
import { getAppUserSession, getAppUserTokens } from '@frontegg/nextjs/app';
export const ServerSession = async () => {
const userSession = await getAppUserSession();
const tokens = await getAppUserTokens();
return (
<div>
<div>user session server side: {JSON.stringify(userSession)}</div>;
<div>user tokens server side: {JSON.stringify(tokens)}</div>
</div>
);
};
You're all set!
Updated about 1 month ago