Files
pedwfrontend/pages/api/auth/[...nextauth].js
T
Robert Bond 0ff2d69ba6 Merged PR 2290: add guard rail to check for locale and ensure verify request is language spec...
add guard rail to check for locale and ensure verify request is language specific

Related work items: #22303
2026-05-05 08:25:17 +00:00

292 lines
9.0 KiB
JavaScript

/**
* @swagger
* /api/auth/[...nextauth]:
* get:
* summary: Phase 2
* tags: [Login]
* description: NextAuth
* responses:
* 200:
* description: Success
*/
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";
import NextAuth from "next-auth";
import EmailProvider from "next-auth/providers/email";
import { consoleLogger } from "../../../actions/core/logger";
import { getPortalLogin } from "../../../actions/services/accountService";
const prisma = new PrismaClient();
const WELSH_LANGUAGE_CODE = 846040000;
const appendParamsAndPathToNewUrl = (fromUrl, toUrl) => {
const fromUrlObj = new URL(fromUrl);
const params = fromUrlObj.searchParams;
const toUrlObj = new URL(toUrl);
toUrlObj.pathname = fromUrlObj.pathname;
params.forEach((value, key) => {
if (!toUrlObj.searchParams.has(key)) {
toUrlObj.searchParams.append(key, value);
}
});
return toUrlObj.toString();
};
// const resolveRequestLocale = (req) => {
// const locale =
// req?.body?.locale || req?.query?.locale || req?.cookies?.pedw_locale;
// return locale === "cy" ? "cy" : "en";
// };
const resolveCrmLocale = async (email) => {
if (!email) return null;
try {
const portalUserObj = await getPortalLogin(email);
const preferredLanguage =
portalUserObj?.value?.[0]?.pinswg_preferredlanguage;
if (preferredLanguage === WELSH_LANGUAGE_CODE) {
return "cy";
}
if (preferredLanguage != null) {
return "en";
}
return null;
} catch (error) {
consoleLogger(error);
return null;
}
};
const resolveEffectiveLocale = async (req, email) => {
const crmLocale = await resolveCrmLocale(email);
if (crmLocale) return crmLocale;
return resolveRequestLocale(req);
};
const buildLocalizedVerificationUrl = ({ url, email, effectiveLocale }) => {
const { host, protocol, searchParams } = new URL(url);
const baseDomain = `${protocol}//${host}`;
const newURL =
effectiveLocale === "cy"
? baseDomain +
"/api/auth/callback/email?callbackUrl=" +
encodeURIComponent(baseDomain + "/cy") +
"&token=" +
searchParams.get("token") +
"&email=" +
encodeURIComponent(email) +
"&locale=" +
effectiveLocale
: url;
return appendParamsAndPathToNewUrl(url, newURL);
};
const getLocaleFromCallbackUrl = (callbackUrl) => {
if (!callbackUrl) return null;
try {
const parsed = new URL(callbackUrl);
const locale = parsed.searchParams.get("locale");
if (locale === "cy" || parsed.pathname.startsWith("/cy")) {
return "cy";
}
if (locale === "en") {
return "en";
}
return null;
} catch {
return null;
}
};
const resolveRequestLocale = (req) => {
const directLocale =
req?.body?.locale || req?.query?.locale || req?.cookies?.pedw_locale;
if (directLocale === "cy") return "cy";
if (directLocale === "en") return "en";
const callbackLocale =
getLocaleFromCallbackUrl(req?.body?.callbackUrl) ||
getLocaleFromCallbackUrl(req?.query?.callbackUrl) ||
getLocaleFromCallbackUrl(
req?.cookies?.["__Secure-next-auth.callback-url"]
);
return callbackLocale === "cy" ? "cy" : "en";
};
const authOptions = (req, res) => {
const requestLocale = resolveRequestLocale(req);
return {
providers: [
{
id: "emailAPI",
name: "emailAPI",
type: "email",
async sendVerificationRequest({ identifier: email, url }) {
const effectiveLocale = await resolveEffectiveLocale(
req,
email
);
console.log(
"============================================================\n",
"verification url API: " + url + "\n",
"============================================================\n"
);
const formURL = buildLocalizedVerificationUrl({
url,
email,
effectiveLocale
});
console.log(
"============================================================\n",
"new verification url----: " + formURL + "\n",
"============================================================\n"
);
return res
.writeHead(200, { "Content-Type": "application/json" })
.json({ url: formURL });
}
},
EmailProvider({
maxAge: 2 * 60 * 60,
async sendVerificationRequest({ identifier: email, url }) {
const templateId = "b1b5704b-9bb8-4deb-a75c-d887ca902661";
const templateIdcy = "0614ce53-cd5f-421f-a1a5-8c8486a9113a";
const effectiveLocale = await resolveEffectiveLocale(
req,
email
);
console.log(
"============================================================\n",
"verification url----: " + url + "\n",
"============================================================\n"
);
const formURL = buildLocalizedVerificationUrl({
url,
email,
effectiveLocale
});
console.log(
"============================================================\n",
"new verification url----: " + formURL + "\n",
"============================================================\n"
);
const personalisation = {
emailAddress: email,
signInLink: formURL,
linkExpiry: 2 * 60 * 60
};
const reference = "PEDW-SIGNIN";
var NotifyClient =
require("notifications-node-client").NotifyClient;
const notifyClient = new NotifyClient(
process.env.NOTIFY_API_KEY
);
try {
await notifyClient.sendEmail(
effectiveLocale === "cy"
? templateIdcy
: templateId,
email,
{
personalisation,
reference
}
);
} catch (error) {
consoleLogger(error);
}
}
})
],
adapter: PrismaAdapter(prisma),
secret: process.env.NEXTAUTH_SECRET,
session: {
strategy: "database",
jwt: true,
pages: {},
theme: "dark",
debug: true,
maxAge: 30 * 60,
updateAge: 5 * 60
},
cookies: {
callbackUrl: {
name: `__Secure-next-auth.callback-url`,
options: {
sameSite: "lax",
path: "/",
secure: true
}
}
},
pages: {
signIn: (requestLocale === "cy" ? "/cy" : "") + "/auth/signin",
error: (requestLocale === "cy" ? "/cy" : "") + "/auth/error",
verifyRequest:
(requestLocale === "cy" ? "/cy" : "") + "/auth/verify-request",
newUser: (requestLocale === "cy" ? "/cy" : "") + "/account/register"
},
callbacks: {
session: async (session, user) => {
console.log("callback in auth", session, user);
return Promise.resolve(session);
},
redirect({ url, baseUrl }) {
console.log("baseurl:", url, baseUrl);
if (url.startsWith("/")) return `${baseUrl}${url}`;
if (new URL(url).origin === baseUrl) return url;
const newUrl =
requestLocale === "cy"
? process.env.CY_API_ROOT
: process.env.NEXTAUTH_URL;
const updatedUrl = appendParamsAndPathToNewUrl(url, newUrl);
console.log(updatedUrl);
return updatedUrl;
}
}
};
};
const NextAuthPEDW = (req, res) => {
return NextAuth(req, res, authOptions(req, res));
};
export default NextAuthPEDW;