---
title: "Sharing authentication between Next.js projects with NextAuth"
url: https://monogram.io/blog/sharing-authentication-between-nextjs-projects-with-nextauth
date: 2022-09-16
authors: ["Chalo"]
---

# Sharing authentication between Next.js projects with NextAuth

**Published:** Sep 16, 2022 | **Authors:** Chalo, Senior Engineer | **Categories:** Engineering

---

There are lots of large systems divided into smaller modules and it is very common that some of these modules need to share the same authentication status. In this article we're going to explain how two independent Next.js projects can share the same authentication status using NextAuth.js.

If you are in a hurry and want to go straight to the code, [here is the repo](https://github.com/monogramdesign/shared-next-auth).

Now, let's suppose that you have a company website, mainly for marketing purposes but then the company wants to add a module where the users have a more personalized experience, for this the users will need to create an account and then sign in to the site but the session status should be visible also from the website.

Let's start with two Next.js projects, one for the website and one for the user portal. The website is going to be our main project, that is, it will be on our main domain. i.e. **example.com**. The user portal will live in a subdirectory of the main domain like **example.com/portal**. This is important because we are basing this on what Vercel calls Next.js [Multi Zones](https://nextjs.org/docs/advanced-features/multi-zones).

## Running both projects in different ports

Before we start, I recommend to modify your **package.json** files in the projects to be able to run both projects at the same time but in different ports. In this case we're just going to modify the port in which the website will run, so in the **scripts **section we change the **dev** script to:

```json
...

"scripts": {
    "dev": "next dev -p 4000",
    ...
}

...
```

## Portal project configuration

We'll start setting up the portal project. This is the project that will provide user specific features, so here's where users will need to create an account and log in. Therefore, here's where we will manage user's sessions with NextAuth.

The first step is to add the **basePath** so the root of the project will be **/portal** instead of **/**. This is done in the **next.config.js** file.

```
// portal/next.config.js

module.exports = {
  // ...

  basePath: "/portal",

  // ...
};
```

*👉 Remember to restart your server after making changes to the* ***next.config.js*** *file*

Now, if we run the project we can confirm that the **basePath** is being applied. If we go to **http://localhost:3000/** we will get a **404** error but if we go to **http://localhost:3000/portal** our site will be running there.

**NOTE:** The portal project is running in the default port which is 3000.

The next step is to add NextAuth to our project and set it up according to the docs:

**1.** [**Install NextAuth**](https://next-auth.js.org/getting-started/example#install-nextauth)

**2. Add the environment variables**

```bash
# portal/.env.local

GITHUB_ID=[COPY VALUE FROM YOUR GITHUB OAUTH APP]
GITHUB_SECRET=[COPY VALUE FROM YOUR GITHUB OAUTH APP]
NEXTAUTH_URL=http://localhost:4000/portal/api/auth
NEXT_PUBLIC_PORTAL_BASE_PATH=/portal
```

If you want to use Github Authentication, you should [add a new OAuth application in your account](https://github.com/settings/applications/new) and copy the values for **GITHUB_ID** and **GITHUB_SECRET**. If you want to [add any other auth provider with NextAuth see the docs](https://next-auth.js.org/configuration/providers/oauth).

Notice that we're setting the **NEXTAUTH_URL** to point to **http://localhost:4000** which is the URL of the website. This is because we want the website to be the main entry point of our site. If it does not makes sense to you, just be patient, this will make sense when we start configuring the Next.js rewrites.

**3.** [**Add the NextAuth API Route**](https://next-auth.js.org/getting-started/example#install-nextauth)

```
// portal/src/pages/api/auth/[...nextauth].js

import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";
export default NextAuth({
  // Configure one or more authentication providers
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_ID,
      clientSecret: process.env.GITHUB_SECRET,
    }),
    // ...add more providers here
  ],
});
```

**4.** [**Add the NextAuth SessionProvider context**](https://next-auth.js.org/getting-started/example#configure-shared-session-state)

```
// portal/src/pages/_app.js

import { SessionProvider } from "next-auth/react";

function App({ Component, pageProps: { session, ...pageProps } }) {
  return (
    <SessionProvider
      session={session}
      basePath={`${process.env.NEXT_PUBLIC_PORTAL_BASE_PATH}/api/auth`}
    >
      <Component {...pageProps} />
    </SessionProvider>
  );
}

export default App;
```

**5.** [**Frontend - Add React Hook**](https://next-auth.js.org/getting-started/example#frontend---add-react-hook)

We can use the **useSession** React hook from NextAuth to create a **LoginButton** component which will show us a button to start the Github authentication process. After the user has signed in this component will show us the user information and will show a sign out button too.

```
// portal/src/components/LoginButton.jsx

import { useSession, signIn, signOut } from "next-auth/react";

export default function LoginButton() {
  const { data: session } = useSession();

  if (session) {
    return (
      <>
        Signed in as {session.user.email} <br />
        <button onClick={() => signOut()}>Sign out</button>
      </>
    );
  }

  return (
    <>
      Not signed in <br />
      <button onClick={() => signIn("github")}>Sign in with Github</button>
    </>
  );
}
```

**6. Add the button to the HomePage**

We're keeping things simple here so our portal home page will show just a message and the **LoginButton** component.

```
// portal/src/pages/index.js

import LoginButton from "../components/LoginButton";

const HomePage = () => (
  <>
    <h1>Welcome to the user portal home page</h1>
    <LoginButton />
  </>
);

export default HomePage;
```

Ok, we have just set up the portal site to manage the user authentication 🎉

But we want to show the session state in the website too, and here is where the interesting part of this article comes. Ready?

## Website project configuration

In order to the website to be aware of the session status, we need to add NextAuth to this project too, similar to what we just did for the portal site, but with a few changes. Let's see.

**NOTE:** We're not adding the NextAuth API route here, because we will use the one we just added to the portal site.

**1.** [**Install NextAuth**](https://next-auth.js.org/getting-started/example#install-nextauth)

**2. Add the environment variables**

```bash
# website/.env.local
NEXTAUTH_URL=http://localhost:4000/portal/api/auth
NEXT_PUBLIC_PORTAL_URL=http://localhost:3000
NEXT_PUBLIC_PORTAL_BASE_PATH=/portal
```

**3.** [**Add the NextAuth SessionProvider context**](https://next-auth.js.org/getting-started/example#configure-shared-session-state)

```
// website/src/pages/_app.js

import { SessionProvider } from "next-auth/react";

function App({ Component, pageProps }) {
  return (
    <SessionProvider
      session={pageProps.session}
      // 👇 Notice that the basePath will be <WEBSITE_URL>/portal/api/auth
      basePath={`${process.env.NEXT_PUBLIC_PORTAL_BASE_PATH}/api/auth`}
    >
      <Component {...pageProps} />
    </SessionProvider>
  );
}

export default App;
```

Notice that NextAuth will use **<WEBSITE_URL>/portal/api/auth** as the **basePath** for all the authentication routes. As we said before, we want the website to be the main entry point to our site. If it seems confusing, again, this will make sense in a little when we configure the rewrites.

**4.** [**Configure the rewrites in Next.js**](https://nextjs.org/docs/api-reference/next.config.js/rewrites) **for the website**

The rewrites for Next.js are configured in the **next.config.js** file. You just need to add the following:

```
// website/next.config.js

module.exports = {

	// ...

  async rewrites() {
    return {
      beforeFiles: [
        // Anything pointing to <WEBSITE_URL>/portal/* will be rewritten to <PORTAL_URL>/portal/*
        // including <WEBSITE_URL>/portal => <PORTAL_URL>/portal
        {
          source: `${process.env.NEXT_PUBLIC_PORTAL_BASE_PATH}/:path*`,
          destination: `${process.env.NEXT_PUBLIC_PORTAL_URL}${process.env.NEXT_PUBLIC_PORTAL_BASE_PATH}/:path*`,
        },
      ],
    };
  },

	// ...

};
```

*👉 Remember to restart your server after making changes to the* ***next.config.js*** *file.*

What we are telling to Next.js here is that any URL that has **/portal** should point to the respective route in the user portal site.

**5.** [**Frontend - Add React Hook**](https://next-auth.js.org/getting-started/example#frontend---add-react-hook)

As we did in the portal project, we are going to add a **LoginButton** component using the **useSession** hook from NextAuth.

```
// portal/src/components/LoginButton.jsx

import { useSession, signIn, signOut } from "next-auth/react";

export default function LoginButton() {
  const { data: session } = useSession();

  if (session) {
    return (
      <>
        Signed in as {session.user.email} <br />
        <button onClick={() => signOut()}>Sign out</button>
      </>
    );
  }

  return (
    <>
      Not signed in <br />
      <button onClick={() => signIn("github")}>Sign in with Github</button>
    </>
  );
}
```

I know, you might be saying *"It is a bad practice to duplicate code”* but I want to keep things simple here. There will be another version of this article but using [Turborepo](https://turborepo.org/) and we will set up everything to be able to share components between both projects.

**6. Add the button to the HomePage**

We're keeping things simple here so our portal home page will show just a message and the **LoginButton** component.

```
// portal/src/pages/index.js

import LoginButton from "../components/LoginButton";

const HomePage = () => (
  <>
    <h1>Welcome to the user portal home page</h1>
    <LoginButton />
  </>
);

export default HomePage;
```

## Adding rewrites for other pages

If you want to add more routes for other pages you may have in the portal site, you just need to add more rewrites here, for example, we will add a new page **/my-results** to the portal site with the following code:

```
// portal/pages/my-results.js

const MyResultsPage = () => {
  return <div>This is were the user results will be listed.</div>;
};

export default MyResultsPage;
```

We can allow our users to go to **<WEBSITE_URL>/my-results** instead of **<WEBSITE_URL>/portal/my-results** by adding another rewrite:

```
// website/next.config.js

// ... other rewrites
{
  source: '/my-results',
  destination: `${process.env.NEXT_PUBLIC_PORTAL_URL}${process.env.NEXT_PUBLIC_LOGIN_BASE_PATH}/my-results`
},
```

*👉 Remember to restart your server after making changes to the* ***next.config.js*** *file.*

We can use the same for all other pages we have in our portal site.

## Fixing NextAuth wrong redirects

There's one problem related to the NextAuth redirects. If an unauthenticated user tries to go to a protected page, NextAuth will redirect the user to **<WEBSITE_URL>/api/auth/…** this will result in a **404** error because there's no NextAuth API Route in the website project only in the portal project.

Let's add protection to our **/my-results** route using the **useSession** hook from NextAuth:

```
// portal/pages/my-results.js

import { useSession } from "next-auth/react";

const MyResultsPage = () => {
  // The { required: true } tells NextAuth that 
  // this page is only accesible to authenticated users
  // unauthenticated users will be redirected
  const { status } = useSession({ required: true });

  if (status === "loading") {
    return <p>Loading...</p>;
  }

  return <div>This is were the user results will be listed.</div>;
};

export default MyResultsPage;
```

Now, if we sign out of the site and try to go to **http://localhost:4000/my-results** or **http://localhost:4000/portal/my-results** we will be redirected to a **404** page.

We can fix this by adding one more rewrite to the website. Anything pointing to **<WEBSITE_URL>/api/auth/*** will be rewritten to **<PORTAL_URL>/portal/api/auth/*** because we want all the auth routes to be managed in the portal site.

```
// website/next.config.js

// ... other rewrites
{
  source: `/api/auth/:path*`,
  destination: `${process.env.NEXT_PUBLIC_PORTAL_URL}${process.env.NEXT_PUBLIC_PORTAL_BASE_PATH}/api/auth/:path*`,
},
```

*👉 Remember to restart your server after making changes to the* ***next.config.js*** *file.*

Done 🥳

This a simple version of what can be done with NextAuth and some Next.js features. The caveat in this version is that we have to duplicate some code i.e. for the **LoginButton** component, but we can also use Turborepo in order to allow component sharing between projects (coming soon).

## Contact Us

[Build what comes next](https://monogram.io/#contact) | Email: [hello+llm@monogram.io](mailto:hello+llm@monogram.io)

Provide your contact details and claim a time to meet. We'll help you do the rest.

Monogram is an Applied AI Studio based in Atlanta that designs and deploys production AI systems — connecting models, data, workflows, and enterprise software to automate real work.

The contact form collects: name, email, company, estimated budget (USD), a project description, and how you heard about Monogram.

Not sure where to start? Tell us what you're trying to automate or build — we'll help you figure out where AI fits.


---

**More content:** [Home](/.md) | [About](/about.md) | [Work](/work.md) | [Engineering](/engineering.md)

Monogram helps companies, organizations, and firms adopt AI by designing and building proof of concepts (POCs), MVPs, intelligent workflows, and production-ready AI applications.

Website designed and developed by [Monogram](https://monogram.io)