## Pages router hosted login quickstart Quickly integrate Frontegg’s login box into your Next.js app with support for Sign In, Sign Up, and SSO — using built-in support for redirects, OpenID Connect, and OAuth2. br Check out the sample package on GitHub br Important notes and prerequisites Frontegg Next.js integration is dependent on SSR (Server Side Rendering). Consequently, Frontegg hooks will not work with Static Site Generation (SSG). **Required minimum versions:** Next.js ≥ 12 Typescript ≥ 3.9.7 @frontegg/nextjs@7.0.0 br Getting your Frontegg subdomain and `clientId` Frontegg creates a unique subdomain and `clientId` 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 `Keys & domains` menu, copy the Frontegg `domain` and `clientId` and use them in `.env.local` file. ### Step 1: Create a Frontegg Next.js app br **If you have an existing app with Next.js, skip this step.** br ``` npx create-next-app@latest my-nextjs-app-name cd my-nextjs-app-name ``` ### Step 2: Install `@frontegg/nextjs` Run the following command to install `@frontegg/nextjs`. br ``` npm install @frontegg/nextjs@latest ``` ``` yarn add @frontegg/nextjs@latest ``` ``` pnpm add @frontegg/nextjs@latest ``` br ### 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. #### Next.js `pages` architecture Create custom Next.js files under the `pages` directory and paste the snippets below. 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. ```typescript import { withFronteggApp } from "@frontegg/nextjs/pages"; function CustomApp({ Component, pageProps }: AppProps) { return ; } export default withFronteggApp(CustomApp, { // hostedLoginBox: true, authOptions: { keepSessionAlive: true // Keeps the session alive by refreshing the JWT in the background }, }); ``` ```typescript import { useCallback, useState } from "react"; import { useAuth, AdminPortal, useAuthActions } from "@frontegg/nextjs"; import { useRouter } from "next/router"; import { useCallback } from "react"; export default function MyPage() { const { user } = useAuth(); const router = useRouter(); const logout = useCallback(() => { router.replace("/account/logout"); }, [router]); return (

My Page

{products}
Logged in as: {user?.name}
Active Tenant: {user?.tenantId}
); } ``` ```typescript 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, }, }; ``` ``` import { FronteggRouter, FronteggRouterProps } from '@frontegg/nextjs/pages'; export const getServerSideProps = FronteggRouterProps; export default FronteggRouter; ``` ### 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 environment's Client ID FRONTEGG_CLIENT_ID='[YOUR_CLIENT_ID]' # Your Frontegg application ID # Available from @frontegg/nextjs@9.2.0 FRONTEGG_APP_ID='[YOUR_APP_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' # By default on each refresh of the page the next middleware will try to refresh the access token even if it’s still valid. The below option allows to disable that behavior and re-use the access token and thus to improve refresh times # Only for pages directory. DISABLE_INITIAL_PROPS_REFRESH_TOKEN=true FRONTEGG_HOSTED_LOGIN='true' # For printing verbose log messages in regards to nextjs middleware activity #FRONTEGG_LOG_LEVEL="debug" # For improving nextjs perfomrance by providing environment public key to the nextjs middleware. # The values can be found under [ENVIRONMENT] → Authentication → Identity provider → OIDC endpoints → JSON web key. # Extract the object from within the `keys` array and use it as the below variable. #FRONTEGG_JWT_PUBLIC_KEY='{"kty":"RSA", "kid":"xxx", "use":"sig", "alg":"RS256", "n":"xxxx", "e":"xxx"}' ``` br Remember to replace the relevant fields in this file with your account's information! br Want to enable client IP forwarding for accurate rate limits? In some deployments, Frontegg may only receive the server’s IP address - especially when using SSR in Next.js. If your use case depends on accurate client IP detection (e.g., for rate limiting, SMS-based MFA, or security rules), consider [enabling IP forwarding](/ciam/sdks/frontend/next/forward-client-ip). br ### Step 5: (optional) `NextRequest` It is recommended to check for the user's session either on the `middleware.ts` or per each page. It is not recommended to use several sources for getting or checking for a user's session. Frontegg uses `getInitialProps` in the Next.js wrapper, therefore, there is no need to call default `getInitialProps` and instead use `context`. Frontegg wrapper holds this data already. br ```typescript import { NextRequest } from 'next/server'; import { handleSessionOnEdge } from '@frontegg/nextjs/edge'; export const middleware = async (request: NextRequest) => { const { pathname, searchParams } = request.nextUrl; const headers = request.headers; // shouldByPassMiddleware from getSessionOnEdge was moved under the hood of handleSessionOnEdge // Additional logic if needed return handleSessionOnEdge({ request, pathname, searchParams, headers }); }; export const config = { matcher: '/(.*)', }; ``` ### Step 6: Redirect to login from a page Alternatively to `middleware.ts`, you can use the Frontegg `withSSRSession` on each page, to redirect users to the login screen if they are not authenticated. ```typescript 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 (

My Page

{products}
{user?.name}
Logged in as: {user?.name}
); } // 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` As an extension of step 6, 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. ```typescript import { GetServerSideProps } from 'next'; import { getSession } from '@frontegg/nextjs/pages'; export default function MyPage({ products }) { return (

My Page

{products}
); } 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: [] } }; }; ```