Reputation: 73
I have a protected route '/new'. Whenever I try to visit this '/new' route, it redirects me to the '/login' route to log in using the Google provider. After I log in, the callback URL is '/new', but instead of redirecting to '/new', it redirects to '/' which is my home route.
I just follow the instruction of next.js learn by adding this file and code:
/api/auth/[...nextauth]/route.ts
export { GET, POST } from '@/auth'
/auth.config.ts
import type { NextAuthConfig } from 'next-auth'
import Google from 'next-auth/providers/google'
export const authConfig = {
pages: {
signIn: '/login'
},
callbacks: {
authorized({ auth, request: { nextUrl } }) {
const isLoggedIn = !!auth?.user
// const isOnDashboardRoutes = nextUrl.pathname.startsWith('/')
const isOnDashboard = nextUrl.pathname === '/'
const isOnNew = nextUrl.pathname.startsWith('/new')
if (isOnDashboard || isOnNew) {
if (isLoggedIn) return true
return false // Redirect unauthenticated users to login page
} else if (isLoggedIn) {
return Response.redirect(new URL('/', nextUrl))
}
return true
}
},
// Add providers with an empty array for now
providers: [Google]
} satisfies NextAuthConfig
/auth.ts
import NextAuth from 'next-auth'
import { authConfig } from './auth.config'
import { PrismaAdapter } from '@auth/prisma-adapter'
import prisma from '@/lib/prismadb'
export const {
handlers: { GET, POST },
auth,
signIn,
signOut
} = NextAuth({
adapter: PrismaAdapter(prisma),
session: { strategy: 'jwt' },
...authConfig
})
/middleware.ts
import NextAuth from 'next-auth'
import { authConfig } from '@/auth.config'
export default NextAuth(authConfig).auth
export const config = {
// https://nextjs.org/docs/app/building-your-application/routing/middleware#matcher
matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)']
}
/action.ts
export async function login() {
await signIn('google')
}
Upvotes: 6
Views: 2772
Reputation: 11
callbacks:{
redirect({ url, baseUrl }) {
const callbackUrl = url.split('?').pop();
const searchParams = new
URLSearchParams(callbackUrl).get('callbackUrl');
if (searchParams != null) return searchParams;
if (url.startsWith('/')) return `${baseUrl}${url}`;
if (new URL(url).origin === baseUrl) return url;
return baseUrl;
}
}
Upvotes: 1
Reputation: 4055
Just to be sure we're on the same page
import { signIn } from "next-auth/react"
After importing the necessary method, let's observe its details
As you see, there's a second parameter; options which is type of SignInOptions
SignInOptions has an option called redirect
Before we dive deeper, first we should set up a next middleware along with next-auth
middleware.ts
import { NextRequest, NextResponse } from "next/server"
import { auth } from "auth"
import { privateRoutes } from "@/contains/contants" // our private routes which can only be accessed by authenticated users
export default auth((request: NextRequest) => {
// @ts-ignore
const { auth } = request // if the user is authenticated or not
const { pathname } = request.nextUrl // the url path
const searchTerm = request.nextUrl.pathname.split("/").slice(0, 2).join("/") // the part of url after the domain
if (privateRoutes.includes(searchTerm)) {
const isLoggedIn = !!auth
// redirect unauthenticated users to login page when they try to access a private route, please mind the callback url
if (!isLoggedIn) {
return NextResponse.redirect(new URL(`/login?callbackUrl=${encodeURIComponent(request.nextUrl.href)}`, request.nextUrl))
}
}
}
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}
Now, let us come back to our login process and finish the job. To do that, we will take control of redirect process using the second parameter I mentioned earlier
"use client"
import { useSearchParams, useRouter } from "next/navigation"
import type { SignInResponse } from "next-auth/lib/client"
import { signIn } from "next-auth/react"
import { Route } from "@/routers/types"
export default function LoginForm() {
const router = useRouter()
const searchParams = useSearchParams()
async function logIn() {
const callbackUrl = searchParams.get("callbackUrl") // this is what we set up in our middleware
signIn("google", { redirect: false }) // we will control the redirect process
.then((res: SignInResponse | undefined) => {
if (!res) {
return
}
if (!res.ok)
alert("Something went wrong!")
else if (res.error) {
console.log(res.error)
if (res.error == "CallbackRouteError")
alert("Could not login! Please check your credentials.")
else
alert(`Internal Server Error: ${res.error}`)
} else {
// THIS IS WHAT YOU ARE AFTER
if (callbackUrl)
router.push(callbackUrl as Route)
else
router.push("/home")
}
})
}
return (
{/*JSX*/}
)
}
That's it! When an unauthenticated user tries to access a private route, e.x. http://localhost:3000/home, it will be redirected to http://localhost:3000/login?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2Fhome path. After logging in, the user will be redirected to http://localhost:3000/home path.
Upvotes: 0