nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
25.02k stars 3.53k forks source link

next/link prefetch cause to infinite redirects when using `withAuth` middleware #6979

Open bboyz269 opened 1 year ago

bboyz269 commented 1 year ago

Environment

nextjs13, nextauth@4.20.1

Reproduction URL

See [How to reproduce] & [Sugguestion]

Describe the issue

Vercel put out a warning here regarding using middleware for authentication.

General speaking, if the state of user authentication when next/link do prefetching versus when user actual clicking differs (IE: unauthenticated then user login in another tab), nextjs always use prefetched data which is redirect to /login page. That combines with ?callbackUrl= params would leads to infinite redirections.

How to reproduce

  1. Create custom /login with callbackUrl params
    
    export const getServerSideProps: GetServerSideProps = async (context) => {
    const session = await getServerSession(context.req, context.res, authConfig)
    if (session) {
    // redirect if authenticated
    return {
        redirect: {
          destination: context.query.calbackUrl ?? '/',
          permanent: false
        }
      }
    }
    // other stuffs ...

}

2. Apply withAuth
```typescript
export { default } from "next-auth/middleware"
  1. Add an next/link to protected route
    <Link href={'/protected'}>Protected</Link>
  2. Open the page with the link, next/link prefetch will received a redirect due to user not authenticated
    /protected -> /login?callbackUrl=/protected
  3. User do authentication in another tab then go back and click the link in the first one Cached response is used, leading to infinite redirects
    /protected -> /login?callbackUrl=/protected -(as user already authenticated)-> 
    /protected -> /login?callbackUrl=/protected -> ...

Expected behavior

User should be redirected to /protected as usual.

Workarounds

Mentioned in the warning, dev can work around by render url based on user's authentication status

function ProtectedLink() {
    const {data: session} = useSession()
    return <Link href={session ? '/protected' : '/login?callbackUrl=/protected'} prefetch={!!session}}
}

But that would take aways most of the reasons to use middleware.

Suggestion

When withAuth failed to check user authentication (unauthenticated, error), don't cache the response.

headers.set('x-middleware-cache', 'no-cache')
rodrigo-arias commented 1 year ago

+1 Experiencing exactly this.

KOCNS1 commented 1 year ago

Any updates? I'm still stuck with this. Feel like I tried everything. I check the default page generated by nextAuth, and nothing different from what I have.

Grymse commented 10 months ago

I still have the same problem ... It seems like this is never being taken care of even though a great deal of people are experiencing it. For me rn I literally have no way of getting around it...

It all works in dev mode, but as soon as I spin up my container, my whole application is crashing as there's an infinite amount of connections being spawned