backend/src/extensions/users-permissions/services/magic-link.ts (view raw)
1import jwt from "jsonwebtoken";
2
3const MAGICLINK_SECRET = process.env.MAGICLINK_SECRET;
4
5interface MagicTokenPayload {
6 email: string;
7 lang: string;
8}
9
10export const generateMagicToken = async (email: string, lang: string) => {
11 const existingUser = await strapi.db
12 .query("plugin::users-permissions.user")
13 .findOne({
14 where: { email },
15 });
16
17 if (existingUser?.provider === "google") {
18 strapi.log.warn(
19 `User ${email} is linked to Google account. Can't login with magic link.`
20 );
21 throw new Error("GoogleAccount");
22 }
23 if (!MAGICLINK_SECRET) throw new Error("No MAGICLINK_SECRET provided");
24
25 strapi.entityService.create("api::log.log", {
26 data: { type: "AUTH_TOKEN_GENERATION", payload: { email, lang } },
27 });
28
29 return jwt.sign({ email, lang }, MAGICLINK_SECRET, { expiresIn: "20m" });
30};
31
32export const verifyMagicToken = (token: string) => {
33 try {
34 const decoded = jwt.verify(token, MAGICLINK_SECRET) as MagicTokenPayload;
35 strapi.entityService.create("api::log.log", {
36 data: {
37 type: "AUTH_TOKEN_VERIFICATION",
38 payload: { email: decoded.email, lang: decoded.lang, valid: true },
39 },
40 });
41 return decoded;
42 } catch (error) {
43 const decoded = jwt.decode(token) as MagicTokenPayload;
44 strapi.entityService.create("api::log.log", {
45 data: {
46 type: "AUTH_TOKEN_VERIFICATION",
47 payload: { email: decoded.email, lang: decoded.lang, valid: false },
48 },
49 });
50 throw new Error("Invalid token");
51 }
52};