users log in using their email via Auth0. Upon login, Auth0 sends a verification email to the user. When the user opens this verification link in the same browser, I aim to establish communication between two tabs. Specifically, I need to send data from the newly opened tab back to the previously active tab.
I have implemented the functionality using the Broadcast Channel API, which allows communication between different browsing contexts such as tabs or windows. However, while the feature works flawlessly in development mode, it fails to function as expected in production mode of Next.js 14.
`const doRedirectCheck = useLatestCallback(async () => {
let bc: broadcastChannelLib.BroadcastChannel | null = null;
let instanceParams: Record<string, any> = {};
if (!preopenInstanceId) {
try {
let error = "";
try {
const { st, e } =
Object.keys(hashParams).length > 0 && hashParams.state
? {
st: hashParams.state,
e: decodeURIComponent(
hashParams.error_description ?? hashParams.error ?? "",
),
}
: Object.keys(queryParams).length > 0 && queryParams.state
? {
st: queryParams.state,
e: queryParams.error ?? "",
}
: { st: "", e: "" };
if (st) {
instanceParams =
JSON.parse(
window.atob(decodeURIComponent(decodeURIComponent(st))),
) || {};
error = e;
}
} catch (e) {
console.error(e);
}
if (instanceParams.redirectToOpener) {
// communicate to window.opener
window.opener.postMessage(
{
channel: "redirect_channel_" + instanceParams.instanceId,
data: {
instanceParams,
hashParams,
queryParams,
},
error,
},
"http://localhost:3000",
);
} else {
if (!instanceParams.instanceId) {
throw new Error("Invalid redirect params");
}
bc = new broadcastChannelLib.BroadcastChannel(
"redirect_channel_" + instanceParams.instanceId,
{ webWorkerSupport: false },
);
bc.addEventListener("message", function (ev) {
console.log("ev", ev);
if (ev.success) {
bc?.close();
console.log("posted", {
queryParams,
instanceParams,
hashParams,
});
setState({
type: "done",
});
} else {
if (ev.error) {
setState({
type: "error",
error: ev.error,
});
} else {
setState({
type: "done",
});
}
}
});
await bc.postMessage({
data: { instanceParams, queryParams, hashParams },
error,
});
}
} catch (err: any) {
console.error(err, "service worker error in redirect");
bc?.close();
setState({
type: "error",
error:
err.error?.message ??
err.message ??
err.error ??
(typeof err === "string"
? err || "Something went wrong"
: "Something went wrong"),
});
}
} else {
// in preopen, awaiting redirect
try {
bc = new broadcastChannelLib.BroadcastChannel(
"preopen_channel_" + preopenInstanceId,
{ webWorkerSupport: false },
);
bc.onmessage = function (ev) {
const { preopenInstanceId: oldId, payload, message } = ev.data;
if (oldId === preopenInstanceId && payload && payload.url) {
window.location.href = payload.url;
} else if (
oldId === preopenInstanceId &&
message === "setup_complete"
) {
bc?.postMessage({
data: {
preopenInstanceId,
message: "popup_loaded",
},
});
}
if (ev.error) {
console.error(ev.error);
bc?.close();
setState({
type: "error",
error: ev.error,
});
}
};
} catch (err: any) {
console.error(err, "service worker error in preopen");
bc?.close();
setState({
type: "error",
error:
err.error?.message ??
err.message ??
err.error ??
(typeof err === "string"
? err || "Something went wrong"
: "Something went wrong"),
});
}
}
});
useEffect(() => {
doRedirectCheck();
}, [doRedirectCheck]);`
In development, everything works correctly.
Amir Hosein is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.