MagicLink working in localhost but not in prod

I'm using Next.Js, Coolify for production. This is the server action use to send the magiclink :
"use server";

import { authClient } from "@/lib/auth-client";
import type { LoginRegisterSchema } from "@/schemas";
import type * as z from "zod/v4";

export async function loginAction(values: z.infer<typeof LoginRegisterSchema>) {
console.log("values: ", values);
const { error, data } = await authClient.signIn.magicLink({
email: values.email,
callbackURL: "/dashboard",
});
console.log("loginAction: ", { error, data });
if (error) {
return {
success: false,
message: "An error occured while sending the email verification !",
};
}
return { success: true, message: "Email sent !" };
}
"use server";

import { authClient } from "@/lib/auth-client";
import type { LoginRegisterSchema } from "@/schemas";
import type * as z from "zod/v4";

export async function loginAction(values: z.infer<typeof LoginRegisterSchema>) {
console.log("values: ", values);
const { error, data } = await authClient.signIn.magicLink({
email: values.email,
callbackURL: "/dashboard",
});
console.log("loginAction: ", { error, data });
if (error) {
return {
success: false,
message: "An error occured while sending the email verification !",
};
}
return { success: true, message: "Email sent !" };
}
This is the error logged : loginAction: { error: { status: 0, statusText: '' }, data: null } Any ideas ? Thank you 🙏
Solution:
use auth.api on the server side. @mrk
Jump to solution
7 Replies
Ping
Ping3mo ago
Can I see your auth config?
mrk
mrkOP2mo ago
import VerificationEmail from "@/emails/verification-email";
import { PrismaClient } from "@prisma/client";
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { APIError, createAuthMiddleware } from "better-auth/api";
import { nextCookies } from "better-auth/next-js";
import { magicLink } from "better-auth/plugins";
import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_KEY);
const prisma = new PrismaClient();
export const auth = betterAuth({
plugins: [
magicLink({
sendMagicLink: async ({ email, url }) => {
try {
await resend.emails.send({
from: "hello <hello@hello.com>",
to: email,
subject: "Verification mail",
react: VerificationEmail(url),
});
} catch (error) {
console.error("Error sending magic link email:", error);
}
},
}),
nextCookies(),
],
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path !== "/login") {
return;
}
if (!ctx.body?.email.endsWith("@hello.com")) {
throw new APIError("BAD_REQUEST", {
error: "Wrong domain name",
});
}
}),
},
});
import VerificationEmail from "@/emails/verification-email";
import { PrismaClient } from "@prisma/client";
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { APIError, createAuthMiddleware } from "better-auth/api";
import { nextCookies } from "better-auth/next-js";
import { magicLink } from "better-auth/plugins";
import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_KEY);
const prisma = new PrismaClient();
export const auth = betterAuth({
plugins: [
magicLink({
sendMagicLink: async ({ email, url }) => {
try {
await resend.emails.send({
from: "hello <hello@hello.com>",
to: email,
subject: "Verification mail",
react: VerificationEmail(url),
});
} catch (error) {
console.error("Error sending magic link email:", error);
}
},
}),
nextCookies(),
],
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path !== "/login") {
return;
}
if (!ctx.body?.email.endsWith("@hello.com")) {
throw new APIError("BAD_REQUEST", {
error: "Wrong domain name",
});
}
}),
},
});
is this the auth config ?
Ping
Ping2mo ago
Yeah When you test on prod, does it get to the sendMagicLink phase? or do you know specifically what's not working?
mrk
mrkOP2mo ago
no it doesn't go to the sendMagicLinkphase. it stops working in the server action, see my first message with this log -> loginAction: { error: { status: 0, statusText: '' }, data: null } couldn't find anything related to the status : 0 in the doc
Ping
Ping2mo ago
Oh I see the issue 😅 You're using authClient on a server action.
Solution
Ping
Ping2mo ago
use auth.api on the server side. @mrk
mrk
mrkOP2mo ago
oh… i see thanks i'll change that
const resend = new Resend(process.env.RESEND_KEY);
const prisma = new PrismaClient();
export const auth = betterAuth({
plugins: [
magicLink({
sendMagicLink: async ({ email, url }) => {
try {
await resend.emails.send({
from: "verif <verification@verif.com>",
to: email,
subject: "Verification mail",
react: VerificationEmail(url),
});
} catch (error) {
console.error("Error sending magic link email:", error);
}
},
}),
nextCookies(),
],
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path !== "/login") {
return;
}
if (!ctx.body?.email.endsWith("@hello.com")) {
throw new APIError("BAD_REQUEST", {
error: "Wrong domain name",
});
}
}),
},
});
const resend = new Resend(process.env.RESEND_KEY);
const prisma = new PrismaClient();
export const auth = betterAuth({
plugins: [
magicLink({
sendMagicLink: async ({ email, url }) => {
try {
await resend.emails.send({
from: "verif <verification@verif.com>",
to: email,
subject: "Verification mail",
react: VerificationEmail(url),
});
} catch (error) {
console.error("Error sending magic link email:", error);
}
},
}),
nextCookies(),
],
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
user: {
additionalFields: {
role: {
type: "string",
},
},
},
hooks: {
before: createAuthMiddleware(async (ctx) => {
if (ctx.path !== "/login") {
return;
}
if (!ctx.body?.email.endsWith("@hello.com")) {
throw new APIError("BAD_REQUEST", {
error: "Wrong domain name",
});
}
}),
},
});
It is now successfully sending mail but when i click on the link i'm redirected to /dashboard (wich is what i want) but I don't have access it adds an entry in my tables, in user, emailVerified says "TRUE" nevermind, it's working well thanks for the help @Ping

Did you find this page helpful?