Overriding Base URL and redirecting to new callback URL not working

I am using the Nextjs SDK with the app router. My app can be accessed from different subdomains e.g. test.app.com, test1.app.com, test2.app.com.

test1.app.com is the AUTH0_BASE_URL set in my .env file. I can login without issues on that subdomain. However, when I try on other sub dimains, I get the error:

{"code":"ERR_CALLBACK_HANDLER_FAILURE","name":"CallbackHandlerError","cause":{"error":"unauthorized_client","errorDescription":"The redirect URI is wrong. You sent https://test.app.com, and we expected https://test1.app.com","status":400,"statusCode":400,"openIdState":{"returnTo":"app-dev-test1.app.com/"}},"status":400}

I am not sure what I am missing here. I have attached my full implementation in api/auth/[auth0]/route.ts

import {
  getSession,
  handleAuth,
  handleCallback,
  handleLogin,
  HandlerError,
} from "@auth0/nextjs-auth0";
import type { NextApiRequest, NextApiResponse } from "next";
import { redirect } from "next/navigation";
import { cookies, headers } from "next/headers";

const getFullUrl = () => {
  const protocol = process.env.NODE_ENV !== "development" ? "https" : "http";
  const url = new URL("", `${protocol}://${headers().get('host')}`); 
  return url.origin
};

// Custom login handler to extract invitation and organization from the URL
const customLogin = async (req: NextApiRequest, res: NextApiResponse) => {
  const session = await getSession(req, res);
  

  if (session) {
    // Redirect to home page if user is already logged in
    redirect("/");
  }
  
  // Extracting invitation and organization from the query parameters
  if (req?.url) {
    const redirectUrl = getFullUrl();
    const url = new URL(req?.url, `http://${req.headers.host}`);

    const returnTo = url.searchParams.get("returnTo") || "/";

    const actualUrl = new URL(returnTo, `http://${req.headers.host}`);

    const invitation = actualUrl.searchParams.get("invitation");
    const organization = actualUrl.searchParams.get("organization");
    const organization_name = actualUrl.searchParams.get("organization_name");

    if (invitation && organization && organization_name) {
      // Handling login with dynamic parameters
      try {
        return handleLogin({
          authorizationParams: {
            invitation,
            organization,
            organization_name,
            state: "custom-state",
            // You can add additional fixed or dynamic parameters here
            response_type: "code",
            scope: "openid profile email",
            audience: process.env.AUTH0_API_AUDIENCE,
            redirect_uri: `${redirectUrl}/api/auth/callback`
          },
          returnTo: redirectUrl,
        })(req, res);
      } catch (error) {
        console.log("Error while handling login with custom parameters", error);
      }
    } else {
      // Handling login
      console.log("No Organization or Invitation found. Redirecting to login.");
      console.log({redirectUrl})
      return handleLogin(req, res, {
        authorizationParams: {
          audience: process.env.AUTH0_API_AUDIENCE,
          scope: "openid profile email",
          redirect_uri: `${redirectUrl}/api/auth/callback`
        },
        returnTo: redirectUrl,
      });
    }
  }

  console.log("Redirecting to login.")
  const redirectUrl = getFullUrl();
  console.log(redirectUrl)
  console.log(redirectUrl)
  return handleLogin(req, res, {
    authorizationParams: {
      audience: process.env.AUTH0_API_AUDIENCE,
      scope: "openid profile email",
      redirect_uri: `${redirectUrl}/api/auth/callback`
    },
    returnTo: redirectUrl,
  });
};

const afterCallback = (req: NextApiRequest, session: any, state: any) => {
  cookies().set("_session", session?.accessToken, {
    httpOnly: true,
    secure: process.env.NODE_ENV !== "development",
    path: "/",
    maxAge: session?.accessTokenExpiresAt,
  });

  return session;
};

// export const GET = handleAuth();
export const GET = handleAuth({
  login: customLogin,
  onError: (req: any, error: HandlerError) => {
    console.error("Error while handling authentication: ", JSON.stringify(error));
    console.log("")
    // console.log(req)
    console.log("")
    // const url = `${req.url.split("/api")[0]}/error?${req.url.split("?")[1]}`;
    const url = `${getFullUrl()}/error?${req.url.split("?")[1]}`;
    console.error("Redirecting to: ", url)
    console.log("")
    redirect(url);
  },
  callback: handleCallback({ afterCallback }),
});

Here is the solution:

That’s pretty much what I came up with, too!

export const initializeAuth0 = (
req: NextApiRequest | IncomingMessage
): ReturnType => {
return initAuth0({
baseURL:
req.headers.origin ||
${process.env.NODE_ENV === "development" ? "http" : "https"}://${ req.headers.host },
});
};
Being able to override the baseURL per domain was the only way I could avoid the checks.state error. It also meant I could eliminate a lot of boilerplate in my […auth0].ts route

import type { NextApiRequest, NextApiResponse } from “next”;
import { initializeAuth0 } from “…/…/…/src/lib/auth0”;

export default function auth(
req: NextApiRequest,
res: NextApiResponse
): void | Promise {
const auth0 = initializeAuth0(req);
return auth0.handleAuth()(req, res);
}

type or paste code here