Nextjs13: Not redirected after signin by the middleware.ts file in the deployed version of the project.
Environment
System: OS: macOS 13.0.1 CPU: (8) arm64 Apple M1 Memory: 365.48 MB / 8.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 18.17.1 - /usr/local/bin/node npm: 9.6.7 - /usr/local/bin/npm next: 13.4.9 -> 14.0.0 next-auth: 4.20.1 Browsers: Brave Browser: 117.1.58.137 Chrome: 118.0.5993.117 Safari: 16.1
Reproduction URL
https://github.com/danishrp102/TypeThreads
Describe the issue
So, I have used next-auth for Google authentication. For my nextjs13 project, I have created a middleware.ts file in the src directory for route protection. I have no problems with the app functioning in development, but after I deploy it to vercel, I am not able to access the dashboard after successful signIn. I can say that I am successfully signed in because the Redis database shows the user stored in the DB. Please help me to solve this issue.
How to reproduce
Head over to https://type-threads.vercel.app/ and try to signIn through your google account
OR
Visit my repository https://github.com/danishrp102/TypeThreads to clone it and run it locally. This would require you to create an upstash account, pusher account and install all the dependencies as mentioned int the package.json
OR
This is my middleware.ts file:
// prevents relogins and accessing sensitive routes without logins
import { getToken } from "next-auth/jwt";
import { withAuth } from "next-auth/middleware";
import { NextResponse } from "next/server";
export default withAuth(
async function middleware(req) {
const pathname = req.nextUrl.pathname;
// Manage the route protection
const isAuth = await getToken({ req });
const isLoginPage = pathname.startsWith('/login');
const sensitiveRoutes = ['/dashboard'];
const isAccessingSensitiveRoutes = sensitiveRoutes.some((route) => pathname.startsWith(route));
if (isLoginPage) {
if (isAuth) {
return NextResponse.redirect(new URL('/dashboard', req.url));
}
return NextResponse.next();
}
if (!isAuth && isAccessingSensitiveRoutes) {
return NextResponse.redirect(new URL('/login', req.url));
}
if (pathname === '/') {
return NextResponse.redirect(new URL('/dashboard', req.url));
}
}, {
callbacks: {
async authorized() {
return true;
},
}
}
)
export const config = {
matcher: ['/', '/login', '/dashboard/:path*']
}
Add this to your project and implement simple google authentication using next-auth.
Expected behavior
I should be able to successfully signIn, but I am not redirected to the dashboard. Instead, the page is refreshed while the token values are apparently not received in the middleware file in the deployed version.
Im following the steps here https://nextjs.org/learn/dashboard-app/adding-authentication using the new NextJS 14 with the next-auth@beta and even after Credentials authorize return a user, it doesn't redirect to the dashboard page.
export const { auth, signIn, signOut } = NextAuth({
...authConfig,
providers: [
Credentials({
async authorize(credentials) {
// ...
if (parsedCredentials.success) {
const { email, password } = parsedCredentials.data;
const user = await getUser(email);
if (!user) return null;
const passwordsMatch = await bcrypt.compare(password, user.password);
if (passwordsMatch) return user; // <<< Passwords match and the user is returned.
}
console.log('Invalid credentials');
return null;
},
}),
],
});
Hi! Having the same issue as @emersonbroga! To reproduce you can simply clone the next-learn final example and try to run it using a custom API.
It seems like the user on the auth object in the auth.config.ts is never populated which causing this test : const isLoggedIn = !!auth?.user; to fail and return false
For @emersonbroga and @Kayoshi-dev, the fix is to add AUTH_URL=http://localhost:3000/api/auth to your .env, alongside AUTH_SECRET
The same issue also happen to the signOut, my workaround for sign out is to redirect manually in middleware.
But I yet to find a workaround for signIn, the only way is to use the client-side signIn from next-auth/react.
@Kayoshi-dev @emersonbroga
I was having the same issue but I've managed to fix the null auth object problem by removing the .next folder and add AUTH_URL to the .env file
I finally find out in my case.
When I signIn, in my server action, I was not throwing the error in my catch witch cause the redirectTo to not work correctly (I don't know why)
So just do that instead:
try {
await signIn("credentials", {
email,
password,
redirectTo: LOGIN_REDIRECT,
});
} catch (error) {
if (error instanceof AuthError) {
switch (error.type) {
case "CredentialsSignin":
return { error: "Invalid credentials" };
default:
return { error: "Something went wrong" };
}
}
// HERE
throw error
}
This is not the proper solution but for workaround i used window.location.reoload() way and managed my protected routes in middleware
try {
const response = await signIn('credentials', { ...formData, redirect: false });
console.log(response);
if (!response?.ok && response?.error) {
if (response.error === 'FirstLogin') {
const firstLoginToken = `${getRandomUUID()}-${getRandomUUID()}`.replace(/-/g, '');
const { error } = await createToken(formData.email, firstLoginToken);
if (error) {
form.reset();
setSubmitError(error);
}
router.replace(`/setup-password/${firstLoginToken}`);
return;
}
form.reset();
setSubmitError(response?.error);
return;
}
await sleep(200);
window.location.reload();
} catch (error) {
console.log(error);
}
};```
If any one have better approach or solution please reply because I am facing issue
I finally find out in my case.
When I signIn, in my server action, I was not throwing the error in my catch witch cause the redirectTo to not work correctly (I don't know why)
So just do that instead:
try { await signIn("credentials", { email, password, redirectTo: LOGIN_REDIRECT, }); } catch (error) { if (error instanceof AuthError) { switch (error.type) { case "CredentialsSignin": return { error: "Invalid credentials" }; default: return { error: "Something went wrong" }; } } // HERE throw error }
Thank you man i had the same issue but after added the throw error, worked correctly