fix: prevent sign-out crash and surface real email-send failures
- NextAuth session/jwt callbacks no longer return null (the client useSession() hook chokes on a null session, crashing the app on sign-out for deactivated/refreshed sessions) — fixes #57 - UserMenu/Header sign-out handlers close the Manage Users overlay and popover before calling signOut(), and no longer let a rejected signOut() promise go unhandled - Added an app-level error boundary as a safety net for any remaining client render errors - Registration and forgot-password flows now tell the user honestly when the confirmation/reset email failed to send instead of always claiming success — related to #56 - lib/email.ts throws a clear, actionable error when neither SMTP nor Resend is configured, instead of a cryptic SDK error - Documented required SMTP/Resend env vars in DEPLOYMENT_CHECKLIST.md (were missing entirely, which is why no confirmation/reset emails were ever sent in deployed environments) — fixes #56
This commit is contained in:
@@ -99,7 +99,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
token.email = user.email;
|
||||
token.isAdmin = user.isAdmin;
|
||||
token.hasWriteAccess = user.hasWriteAccess;
|
||||
token.exp = Math.floor(Date.now() / 1000) + (24 * 60 * 60); // 24 hours from now
|
||||
token.isActive = true;
|
||||
}
|
||||
|
||||
// Refresh user data from database on token refresh to get latest hasWriteAccess and isActive
|
||||
@@ -117,12 +117,15 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
},
|
||||
});
|
||||
|
||||
if (dbUser) {
|
||||
// Check if user is still active (treat null/undefined as true)
|
||||
if (dbUser.isActive === false) {
|
||||
// User was deactivated, invalidate token
|
||||
return null as any;
|
||||
}
|
||||
if (!dbUser || dbUser.isActive === false) {
|
||||
// User was deactivated or deleted. Flag it on the token instead of
|
||||
// returning `null` here: NextAuth v5's client `useSession()` hook does
|
||||
// not expect a `null` JWT and throws when it encounters one, which is
|
||||
// what caused the sign-out crash (issue #57). The `session` callback
|
||||
// below turns this flag into a clean signed-out session instead.
|
||||
token.isActive = false;
|
||||
} else {
|
||||
token.isActive = true;
|
||||
token.id = dbUser.id.toString();
|
||||
token.isAdmin = dbUser.isAdmin;
|
||||
token.hasWriteAccess = dbUser.hasWriteAccess;
|
||||
@@ -136,9 +139,11 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
return token;
|
||||
},
|
||||
async session({ session, token }) {
|
||||
// If token is null or expired, return null session to force logout
|
||||
if (!token || (token.exp && token.exp < Math.floor(Date.now() / 1000))) {
|
||||
return null as any;
|
||||
// Never return `null` for the whole session object — NextAuth v5's client
|
||||
// hooks assume a `{ user, expires }` shape and crash on `null` (issue #57).
|
||||
// Instead, drop `user` so the client treats this as a normal signed-out state.
|
||||
if (!token || token.isActive === false) {
|
||||
return { ...session, user: undefined } as any;
|
||||
}
|
||||
|
||||
if (session.user) {
|
||||
|
||||
@@ -83,19 +83,25 @@ export async function POST(request: NextRequest) {
|
||||
});
|
||||
|
||||
// Send confirmation email
|
||||
let emailSendFailed = false;
|
||||
try {
|
||||
await sendEmailConfirmation(email, name.trim(), confirmationToken);
|
||||
} catch (emailError) {
|
||||
console.error('Error sending confirmation email:', emailError);
|
||||
// Don't fail registration if email fails, but log it
|
||||
// User can request a resend later
|
||||
// Don't fail registration if email fails, but let the client know so it
|
||||
// doesn't tell the user to "check their email" when nothing was sent
|
||||
// (issue #56). The user can still request a resend later.
|
||||
emailSendFailed = true;
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: 'User created successfully. Please check your email to confirm your account.',
|
||||
message: emailSendFailed
|
||||
? 'Account created, but we could not send the confirmation email right now. Use "Resend confirmation email" on the login screen once you try to sign in.'
|
||||
: 'User created successfully. Please check your email to confirm your account.',
|
||||
user,
|
||||
requiresEmailConfirmation: true
|
||||
requiresEmailConfirmation: true,
|
||||
emailSendFailed,
|
||||
},
|
||||
{ status: 201 }
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user