2fa cookie issues
POST /api/auth/two-factor/send-otp
{"code":"INVALID_TWO_FACTOR_COOKIE","message":"Invalid two factor cookie"}
2 Replies
plugins: [
nextCookies(),
twoFactor({
otpOptions: {
async sendOTP({ user, otp }) {
const html = await render(
TwoFaEmail({ username: user.name, otp: otp })
);
await sendEmail(user.email, "Your 2FA Code", html);
},
},
skipVerificationOnEnable: true,
}),
],
plugins: [
nextCookies(),
twoFactor({
otpOptions: {
async sendOTP({ user, otp }) {
const html = await render(
TwoFaEmail({ username: user.name, otp: otp })
);
await sendEmail(user.email, "Your 2FA Code", html);
},
},
skipVerificationOnEnable: true,
}),
],
const res = (await auth.api.signInEmail({
body: {
email,
password,
},
})) as SignInResponseWith2FA;
if (res.twoFactorRedirect) {
return {
twoFactorRedirect: true,
success: true,
message: "Two-factor authentication is enabled.",
};
}
const res = (await auth.api.signInEmail({
body: {
email,
password,
},
})) as SignInResponseWith2FA;
if (res.twoFactorRedirect) {
return {
twoFactorRedirect: true,
success: true,
message: "Two-factor authentication is enabled.",
};
}
const { success, message, twoFactorRedirect } = await signIn(
email,
password,
token
);
if (twoFactorRedirect) {
const response = await requestOTP();
if (response?.data) {
toast.success("OTP has been sent to your email.");
} else if (response?.error) {
toast.error(response.error.message);
}
}
const { success, message, twoFactorRedirect } = await signIn(
email,
password,
token
);
if (twoFactorRedirect) {
const response = await requestOTP();
if (response?.data) {
toast.success("OTP has been sent to your email.");
} else if (response?.error) {
toast.error(response.error.message);
}
}
import { authClient } from "@/lib/auth-client";
interface OTPResponse {
data?: { status: boolean } | null;
error?: { message: string };
}
type SuccessResponse = Pick<OTPResponse, "data">;
export const requestOTP = async (): Promise<OTPResponse> => {
try {
const response: SuccessResponse = await authClient.twoFactor.sendOtp();
return response;
} catch (error: unknown) {
console.error("Error requesting OTP:", error);
return {
error: { message: "Failed to request OTP. Please try again." },
};
}
};
import { authClient } from "@/lib/auth-client";
interface OTPResponse {
data?: { status: boolean } | null;
error?: { message: string };
}
type SuccessResponse = Pick<OTPResponse, "data">;
export const requestOTP = async (): Promise<OTPResponse> => {
try {
const response: SuccessResponse = await authClient.twoFactor.sendOtp();
return response;
} catch (error: unknown) {
console.error("Error requesting OTP:", error);
return {
error: { message: "Failed to request OTP. Please try again." },
};
}
};
const res = await auth.api.signInEmail({
body: {
email,
password,
},
asResponse: true,
});
console.log(res);
const res = await auth.api.signInEmail({
body: {
email,
password,
},
asResponse: true,
});
console.log(res);
'set-cookie': '__Secure-DO-NOT-SHARE-rage.session_token=KpZqCO3MEUqVNGjdwT6wDIarig2hMfBU.Rk%2F3Xnm5myB83zg3UYDWeEEonsEQHBkVPx6PhmXYXMM%3D; Max-Age=2592000; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax, __Secure-DO-NOT-SHARE-rage.session_token=; Max-Age=0; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax, __Secure-DO-NOT-SHARE-rage.session_data=; Max-Age=0; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax, __Secure-DO-NOT-SHARE-rage-two-factor=2fa-IZ2iNaLrR4z-Ad2SBBQs.4bGwdTxOUbndxuC6XDUVsZ%2BRTax0qKGYef2bXLwUOwc%3D; Max-Age=300; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax',
'Content-Type': 'application/json'
'set-cookie': '__Secure-DO-NOT-SHARE-rage.session_token=KpZqCO3MEUqVNGjdwT6wDIarig2hMfBU.Rk%2F3Xnm5myB83zg3UYDWeEEonsEQHBkVPx6PhmXYXMM%3D; Max-Age=2592000; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax, __Secure-DO-NOT-SHARE-rage.session_token=; Max-Age=0; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax, __Secure-DO-NOT-SHARE-rage.session_data=; Max-Age=0; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax, __Secure-DO-NOT-SHARE-rage-two-factor=2fa-IZ2iNaLrR4z-Ad2SBBQs.4bGwdTxOUbndxuC6XDUVsZ%2BRTax0qKGYef2bXLwUOwc%3D; Max-Age=300; Domain=.rage.wtf; Path=/; HttpOnly; Secure; SameSite=Lax',
'Content-Type': 'application/json'
set-cookie
__Secure-DO-NOT-SHARE-rage.session_token=KpZqCO3MEUqVNGjdwT6wDIarig2hMfBU.Rk%2F3Xnm5myB83zg3UYDWeEEonsEQHBkVPx6PhmXYXMM%3D; Path=/; Expires=Sat, 02 Aug 2025 23:11:01 GMT; Max-Age=2592000; Domain=.rage.wtf; Secure; HttpOnly; SameSite=lax
set-cookie
__Secure-DO-NOT-SHARE-rage.session_token=KpZqCO3MEUqVNGjdwT6wDIarig2hMfBU.Rk%2F3Xnm5myB83zg3UYDWeEEonsEQHBkVPx6PhmXYXMM%3D; Path=/; Expires=Sat, 02 Aug 2025 23:11:01 GMT; Max-Age=2592000; Domain=.rage.wtf; Secure; HttpOnly; SameSite=lax
Solution
nextCookies(), has to be the last plugin