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 }),
});