Repository: auth0/nextjs-auth0 (ts)

Issue:
[DOCS] Vercel (edge) Middleware does not seem to pickup AUTH0_BASE_URL from .env.production in Preview environments
### Checklist

- [X] The issue can be reproduced in the [sample app](https://github.com/auth0-samples/auth0-nextjs-samples/tree/main/Sample-01) (or N/A).
- [X] I have looked into the [README](https://github.com/auth0/nextjs-auth0#readme) and have not found a suitable solution or answer.
- [X] I have looked into the [examples](https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md) and have not found a suitable solution or answer.
- [X] I have looked into the [API documentation](https://auth0.github.io/nextjs-auth0/) and have not found a suitable solution or answer.
- [X] I have searched the [issues](https://github.com/auth0/nextjs-auth0/issues) and have not found a suitable solution or answer.
- [X] I have searched the [Auth0 Community](https://community.auth0.com/c/sdks/5) forums and have not found a suitable solution or answer.
- [X] I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md).

### Description

The [Assigning the AUTH0_BASE_URL](https://github.com/auth0/nextjs-auth0/blob/main/examples/README.md#assigning-the-auth0_base_url) guide is split into:

- Preview deployments
- Production deployments

The preview deployments guide recommends:

```env
# .env.production
AUTH0_BASE_URL=$VERCEL_URL
```

which works perfectly fine until one introduces `middleware.ts` and uses `auth0` in there:

```ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getSession } from '@auth0/nextjs-auth0/edge';

export async function middleware(req: NextRequest) {
  const { pathname } = req.nextUrl;

  if (pathname === '/') {
    const res = NextResponse.next();
    const session = await getSession(req, res);
    const loggedIn = Boolean(session);
    if (!loggedIn) {
      return NextResponse.rewrite(new URL('/guest', req.url));
    }
  }
}

export const config = {
  matcher: ['/'],
};
```

The actual build on Vercel does pickup `.env.production`:

```sh
info  - Loaded env from /vercel/path0/app/.env.production
```

However, this is not seen by the middleware, which crashes (and does the whole app) with:

```
TypeError: "baseURL" is required
    at (../node_modules/.pnpm/@auth0+nextjs-auth0@2.2.2_next@13.1.6/node_modules/@auth0/nextjs-auth0/dist/auth0-session/get-config.js:163:0)
```

I'm not sure, but this could be an issue with Vercel itself?

# Fix

The fix for this is to follow the "Production Deployments" instructions, and add `AUTH0_BASE_URL=$VERCEL_URL` in Vercel's `Settings > Environment Variables`.

# Action Proposed

Even if a bug in Vercel, the [Assigning the AUTH0_BASE_URL](https://github.com/auth0/nextjs-auth0/blob/main/examples/README.md#assigning-the-auth0_base_url) documentation could be updated mentioning the above.

### Reproduction

- Create a nextJS app
- Add `middleware.ts`, add and use `auth0` in there
- Deploy to a preview environment in Vercel

### SDK version

2.2.2

### Next.js version

13.1.6

### Node.js version

18.14.1

Pull request description:
Add prefixed url env for preview deploys on middleware
### 📋 Changes

Add `NEXT_PUBLIC_AUTH0_BASE_URL` env var, which will be picked up when `AUTH0_BASE_URL` is not available.

This is useful when you want to assign a Vercel preview URL to the SDK's base URL in your `.env.production`.

The `NEXT_PUBLIC_` prefix is required for Middleware because it evaluates the env vars at build time and

### 📎 References

https://nextjs.org/docs/pages/api-reference/edge#environment-variables
fixes #1106

Patch:
diff --git a/examples/README.md b/examples/README.md
index 634d1df6..50dfee0e 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -96,18 +96,22 @@ Configure the following environment variables when importing your project or in
 
 For preview deployments you will either want to assign this to:
 
-- **Automatic Deployment URL:** For example `project-d418mhwf5-team.vercel.app` which is defined by the `VERCEL_URL` environment variable.
-- **Automatic Branch URL:** For example `project-git-update-team.vercel.app` which can be constructed using `${VERCEL_GIT_REPO_SLUG}-git-${VERCEL_GIT_COMMIT_REF}-${VERCEL_GIT_REPO_OWNER}.vercel.app`
+- **Automatic Deployment URL:** For example `project-d418mhwf5-team.vercel.app` which is the `VERCEL_URL` environment variable.
+- **Automatic Branch URL:** For example `project-git-update-team.vercel.app` which is the `VERCEL_BRANCH_URL` environment variable.
 
 See here for more information about Vercel's Automatic Urls: https://vercel.com/docs/concepts/deployments/automatic-urls
 
-To do this, make sure **Automatically expose System Environment Variables** is checked in **Settings > Environment Variables** and assign either the Automatic Deployment URL or the Automatic Branch URL to `AUTH0_BASE_URL` in your `.env.production` file. For example:
+To do this, make sure **Automatically expose System Environment Variables** is checked in **Settings > Environment Variables** and assign either the Automatic Deployment URL (`VERCEL_URL`) or the Automatic Branch URL (`VERCEL_BRANCH_URL`) to `NEXT_PUBLIC_AUTH0_BASE_URL` in your `.env.production` file. For example:
 
 ```shell
 # .env.production
-AUTH0_BASE_URL=$VERCEL_URL
+NEXT_PUBLIC_AUTH0_BASE_URL=$VERCEL_URL
 ```
 
+> <strong>Note:</strong> The `NEXT_PUBLIC_` prefix is used so you can specify the base URL in your middleware. You must be on version `2.6.0` or later of this SDK to use `NEXT_PUBLIC_AUTH0_BASE_URL`.
+
+> <strong>Note:</strong> Long URLs (> 63 characters) will get truncated by Vercel. See: https://vercel.com/docs/concepts/deployments/generated-urls#truncation
+
 Unlike other `.env` files, You will need to check in `.env.production` so it should **not** contain any secrets. See how we define `.env.production` in the [kitchen-sink example app](./kitchen-sink-example/.env.production).
 
 ###### Production deployments (or other environments with fixed urls)
diff --git a/examples/kitchen-sink-example/.env.production b/examples/kitchen-sink-example/.env.production
index 3f4f4472..10270b6b 100644
--- a/examples/kitchen-sink-example/.env.production
+++ b/examples/kitchen-sink-example/.env.production
@@ -1,8 +1,10 @@
-# Set the baseUrl for the SDK to the Vercel "Automatic Branch URL" for Preview deploys. Use `${VERCEL_URL}` if you
-# would rather use the 'Automatic Deployment URL' (see: https://vercel.com/changelog/urls-are-becoming-consistent)
+# For preview deploys, set the baseUrl for the SDK to:
+#  - Automatic Deployment URL: `VERCEL__URL` for example project-d418mhwf5-team.vercel.app
+#  - Automatic Branch URL: `VERCEL_BRANCH_URL` for example project-git-update-team.vercel.app
 #
 # For production deploys from the main branch or custom domains which are assigned to a specific branch (see https://vercel.com/docs/custom-domains#assigning-a-domain-to-a-git-branch)
 # you can assign the `AUTH0_BASE_URL` in the 'Environment Variables' section of your project's settings page which will override this.
 #
 # This file should be checked in so should NOT contain any secrets
-AUTH0_BASE_URL=${VERCEL_GIT_REPO_SLUG}-git-${VERCEL_GIT_COMMIT_REF}-${VERCEL_GIT_REPO_OWNER}.vercel.app
+# The `NEXT_PUBLIC_` prefix is only required when you want to use middleware and a `.env.production` file to assign a Vercel preview URL to this SDK's base URL.
+NEXT_PUBLIC_AUTH0_BASE_URL=$VERCEL_BRANCH_URL
diff --git a/examples/kitchen-sink-example/pages/api/shows.ts b/examples/kitchen-sink-example/pages/api/shows.ts
index 993e7456..4dbbd5d9 100644
--- a/examples/kitchen-sink-example/pages/api/shows.ts
+++ b/examples/kitchen-sink-example/pages/api/shows.ts
@@ -6,10 +6,8 @@ export default withApiAuthRequired(async function shows(req, res) {
       scopes: ['read:shows']
     });
 
-    const baseURL =
-      process.env.AUTH0_BASE_URL?.indexOf('http') === 0
-        ? process.env.AUTH0_BASE_URL
-        : `https://${process.env.AUTH0_BASE_URL}`;
+    const baseUrlOrDomain = process.env.AUTH0_BASE_URL || process.env.NEXT_PUBLIC_AUTH0_BASE_URL;
+    const baseURL = baseUrlOrDomain?.indexOf('http') === 0 ? baseUrlOrDomain : `https://${baseUrlOrDomain}`;
 
     // This is a contrived example, normally your external API would exist on another domain.
     const response = await fetch(baseURL + '/api/my/shows', {
diff --git a/src/config.ts b/src/config.ts
index fbc21eed..81eda46a 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -66,6 +66,8 @@ export interface BaseConfig {
    * You can also use the `AUTH0_BASE_URL` environment variable.
    * If you provide a domain, we will prefix it with `https://`. This can be useful when assigning it to
    * `VERCEL_URL` for Vercel deploys.
+   *
+   * `NEXT_PUBLIC_AUTH0_BASE_URL` will also be checked if `AUTH0_BASE_URL` is not defined.
    */
   baseURL: string;
 
@@ -487,7 +489,7 @@ export const getConfig = (params: ConfigParameters = {}): { baseConfig: BaseConf
   // Don't use destructuring here so that the `DefinePlugin` can replace any env vars specified in `next.config.js`
   const AUTH0_SECRET = process.env.AUTH0_SECRET;
   const AUTH0_ISSUER_BASE_URL = process.env.AUTH0_ISSUER_BASE_URL;
-  const AUTH0_BASE_URL = process.env.AUTH0_BASE_URL;
+  const AUTH0_BASE_URL = process.env.AUTH0_BASE_URL || process.env.NEXT_PUBLIC_AUTH0_BASE_URL;
   const AUTH0_CLIENT_ID = process.env.AUTH0_CLIENT_ID;
   const AUTH0_CLIENT_SECRET = process.env.AUTH0_CLIENT_SECRET;
   const AUTH0_CLOCK_TOLERANCE = process.env.AUTH0_CLOCK_TOLERANCE;


Test patch:
diff --git a/tests/config.test.ts b/tests/config.test.ts
index a681ace6..ba8b6657 100644
--- a/tests/config.test.ts
+++ b/tests/config.test.ts
@@ -1,16 +1,20 @@
 import { BaseConfig, NextConfig, getConfig } from '../src/config';
 
-const getConfigWithEnv = (env: any = {}, opts?: any): { baseConfig: BaseConfig; nextConfig: NextConfig } => {
+const getConfigWithEnv = (
+  env: any = {},
+  opts?: any,
+  defaultEnv = {
+    AUTH0_SECRET: '__long_super_secret_secret__',
+    AUTH0_ISSUER_BASE_URL: 'https://example.auth0.com',
+    AUTH0_BASE_URL: 'https://example.com',
+    AUTH0_CLIENT_ID: '__test_client_id__',
+    AUTH0_CLIENT_SECRET: '__test_client_secret__'
+  }
+): { baseConfig: BaseConfig; nextConfig: NextConfig } => {
   const bkp = process.env;
   process.env = {
     ...process.env,
-    ...{
-      AUTH0_SECRET: '__long_super_secret_secret__',
-      AUTH0_ISSUER_BASE_URL: 'https://example.auth0.com',
-      AUTH0_BASE_URL: 'https://example.com',
-      AUTH0_CLIENT_ID: '__test_client_id__',
-      AUTH0_CLIENT_SECRET: '__test_client_secret__'
-    },
+    ...defaultEnv,
     ...env
   };
   try {
@@ -235,6 +239,37 @@ describe('config params', () => {
     });
   });
 
+  test('should fallback to NEXT_PUBLIC_ prefixed base URL', () => {
+    expect(
+      getConfigWithEnv(
+        {
+          NEXT_PUBLIC_AUTH0_BASE_URL: 'public-foo.auth0.com'
+        },
+        undefined,
+        {
+          AUTH0_SECRET: '__long_super_secret_secret__',
+          AUTH0_ISSUER_BASE_URL: 'https://example.auth0.com',
+          AUTH0_BASE_URL: '',
+          AUTH0_CLIENT_ID: '__test_client_id__',
+          AUTH0_CLIENT_SECRET: '__test_client_secret__'
+        }
+      ).baseConfig
+    ).toMatchObject({
+      baseURL: 'https://public-foo.auth0.com'
+    });
+  });
+
+  test('should prefer AUTH0_BASE_URL without the prefix', () => {
+    expect(
+      getConfigWithEnv({
+        AUTH0_BASE_URL: 'foo.auth0.com',
+        NEXT_PUBLIC_AUTH0_BASE_URL: 'bar.auth0.com'
+      }).baseConfig
+    ).toMatchObject({
+      baseURL: 'https://foo.auth0.com'
+    });
+  });
+
   test('should accept optional callback path', () => {
     const { baseConfig, nextConfig } = getConfigWithEnv({
       AUTH0_CALLBACK: '/api/custom-callback'