Embed Next.js

Overview

In this quickstart, we will embed Frontegg login box to your Next.js application. In just 5 minutes from now, your application will have a login box with Sign in, Sign up, and SSO. All this with just a few lines of code!


The code in the sample below is available in our Frontegg Samples repository


⚡ Before you start: ⚡

📘

Getting your Frontegg subdomain and clientId

Frontegg creates a unique subdomain and client id for every environment created on the account. In order to retrieve the clientId subdomain that will act as the FRONTEGG_BASE_URL in the integration, navigate to your environment 'Settings' menu, copy the Frontegg domain and clientId and use them in .env.local file.


STEP 1: Create Frontegg Next.js sample app.

📘

If you have an existing app with Next.js app, skip this step.


To create a new app based on our sample or Next.js template or a new Next.js app, run the below commands.
// Next.js 13 will be installed by default

npx [email protected] my-nextjs-app-name

// Next.js with experimental app directory

npx [email protected] --experimental-app my-nextjs-app-name

cd my-nextjs-app-name
// Next.js 13 will be installed by default

yarn create next-app my-nextjs-app-name

// Next.js with experimental app directory

yarn [email protected] --experimental-app my-nextjs-app-name

cd my-nextjs-app-name

STEP 2: Install

Run the following command to install @frontegg/nextjs.

📘

Support for Next.js 13 is available from @frontegg/[email protected]


npm install @frontegg/[email protected]
yarn add @frontegg/[email protected]

🚧

Breaking Changes from v5

@frontegg/nextjs v5 and above have been updated to support nextjs SSR, and thus have breaking changes.

📘

Note - the files in this guide are in typescript - if you are working in js, simply change the file types and remove the typing

STEP 3: Configure the App file, Router, Middleware files

When integrating Next.js application with Frontegg, Next.js custom app and several files should be added. Make sure that these exist in the project you cloned from our sample or created.


For Next.js 12

Create custom Next.js files under pages directory and paste the snippets below:


📘

Existing custom Next.js app

If you have a custom app already (the file _app.tsx exists), wrap and replace the default export component with withFronteggApp function and pass your original component.


import { withFronteggApp } from '@frontegg/nextjs';

function CustomApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default withFronteggApp(CustomApp, 
  {
    hostedLoginBox: false, 
    authOptions: {
    // keepSessionAlive: true // Uncomment this in order to maintain the session alive
    }
});
export { fronteggMiddleware as default } from '@frontegg/nextjs';
export {
  FronteggRouter as default,
  FronteggRouterProps as getServerSideProps,
} from '@frontegg/nextjs';

For Next.js 13

Create custom Next.js files under app directory and paste the snippets below. The ./pages/api/frontegg/[...frontegg-middleware].ts file should stay in pages directory:


"use client";
import { useAuth } from "@frontegg/nextjs";

export const ClientComponent = ({ baseUrl }: { baseUrl?: string }) => {

  const { user, isAuthenticated } = useAuth();

  const logout = () => {
    window.location.href = `${baseUrl}/account/logout`;
  };

  return (
    <div className="App">
      { isAuthenticated ? (
        <div>
          <div>
            <img src={user?.profilePictureUrl} alt={user?.name}/>
          </div>
          <div>
            <span>Logged in as: {user?.name}</span>
          </div>
          <div>
            <button onClick={() => alert(user?.accessToken)}>What is my access token?</button>
          </div>
            <button onClick={() => logout()}>Click to logout</button>
          </div>
      ) : (
        <div>
          Not logged in
        </div>
      )}
    </div>
  );
};
import { getSession } from "@frontegg/nextjs/server";

export const ServerComponent = async () => {
  const session = await getSession();

  return <pre>{JSON.stringify(session, null, 2)}</pre>;
};
import { ClientComponent } from "./ClientComponent";
import { ServerComponent } from "./ServerComponent";

export default function MainPage() {
    const baseUrl = process.env["FRONTEGG_APP_URL"]

  return (
    <div>
      <h3>Next JS application with frontegg</h3>
      <ServerComponent />
      <ClientComponent baseUrl={baseUrl}/>
    </div>
  );
}
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 (
    //@ts-ignore
    <FronteggAppProvider authOptions={authOptions} hostedLoginBox={false}>
      <html>
        <head></head>
        <body>{children}</body>
      </html>
    </FronteggAppProvider>
  );
}
export { FronteggAppRouter as default } from '@frontegg/nextjs/client';
export { fronteggMiddleware as default } from '@frontegg/nextjs';

🚧

File Names

Next.js works with pages (Next.js 12) and app directories (Next.js 13).

The locations and the files names should be exactly as written on the file names, including the brackets and the three dots.

For Next.js 12 - ./pages/[...frontegg-router].tsx, ./pages/api/frontegg/[...frontegg-middleware].ts and ./pages/_app.tsx.

For Next.js 13 - ./app/layout.tsx , ./app/[...frontegg-router]/page.tsx, ./app/ServerComponent.tsx, app/ClientComponent.tsx.


STEP 4 Setup Environment

To setup your Next.js application to communicate with Frontegg, you have to create a new file named .env.local under your root project directory, this file will be used to store environment variables that will be used, configuration options:

# The AppUrl you set during integration - this is to tell Frontegg your application hostname
FRONTEGG_APP_URL='http://localhost:3000'

# The Frontegg domain is your unique URL to connect to the Frontegg gateway
FRONTEGG_BASE_URL='https://[YOUR_SUBDOMAIN].frontegg.com'

# Your Frontegg application's Client ID
FRONTEGG_CLIENT_ID='[YOUR_CLIENT_ID]'

# The statless session encruption password, used to encrypt
# jwt before sending it to the client side.
#
# For quick password generation use the following command:
#    node -e "console.log(crypto.randomBytes(32).toString('hex'))"
FRONTEGG_ENCRYPTION_PASSWORD='[64_CHAR_SESSION_ENCRYPTION_PASSWORD]'

# The statless session cookie name - you should not change this
FRONTEGG_COOKIE_NAME='fe_session'

Remember to replace the relevant fields in this file with your personal information!

STEP 5 (optional) NextRequest

📘

Support for NextJS middleware is available from @frontegg/nextjs v6.4.0

To prevent access of an unauthenticated user to all routes, use Next.js middlewares.

NOTE: If you were using Middleware prior to 12.2, please see the upgrade guide.

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { getSession } from '@frontegg/nextjs/edge';

export const middleware = async (request: NextRequest) => {
  const session = await getSession(request);
  const isAuthRoute = request.url.endsWith("/")

  if(!session && isAuthRoute){
    // redirect unauthenticated user to /account/login page
    return NextResponse.redirect(new URL('/account/login', request.url))
  }
  
  return NextResponse.next();
};

export const config = {
  matcher: "/(.*)",
};

STEP 6: Redirect to login

You can use the Frontegg withSSRSession, you can automatically redirect users to the login screen if they are not authenticated.

For Next.js 12 with pages directory.

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: { } };
  }
);

STEP 7 (optional) getSession

For any page that requires an AccessToken on the server side (e.g. you'd like to load the data only if a user is logged in), you can use the getSession method. Remember to replace external with the link to your external service.

For Next.js 12 with pages directory.

import { GetServerSideProps } from 'next';
import { getSession } from '@frontegg/nextjs';

export default function MyPage({ products }) {
  return (
    <div>
      <h1>My Page</h1>
      {products}
    </div>
  );
}

export const getServerSideProps: GetServerSideProps = async (context) => {
  const session = await getSession(context.req);
  if (session) {
    const { data } = await fetch('{external}/product', {
      headers: {
        Authorization: 'bearer ' + session.accessToken,
      },
    });
    return { props: { products: data } };
  }

  return { props: { products: [] } };
};

STEP 8 (optional) customLoader

import "../styles/globals.css";

export default withFronteggApp(CustomApp, 
  {
    hostedLoginBox: false, 
    customLoader: true,
    authOptions: {
    // keepSessionAlive: true // Uncomment this in order to maintain the session alive
    }
});

Add _document.tsx file under the pages folder.

import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
        <div className="custom-loader"> I am a custom loader!</div>
      </body>
    </Html>
  );
}

Add the following styles to styles/globals.css:

.custom-loader {
    width: 100vw;
    height: 100vh;
    background: red;
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    text-align: center;
    justify-content: center;
    align-items: center;
    font-size: 50px;
    color: white;
}

body.frontegg-loading .custom-loader {
    display: flex;
}

  • Signup screen is at http://localhost:3000/account/sign-up
  • Login screen is at http://localhost:3000/account/login

If you are already logged in, go to http://localhost:3000/account/logout and log out.

Give it a try now!

Open http://localhost:3000/account/sign-up and sign up with your first user.