Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Next13/App directory]: Root layout requires refresh for middleware to detect session with signInWithPassword() #393

Closed
hjaber opened this issue Dec 2, 2022 · 3 comments
Labels
bug Something isn't working

Comments

@hjaber
Copy link

hjaber commented Dec 2, 2022

Bug report

After authenticating with signInWithPassword(), you must refresh the page for middleware to pick up the session.

The example repo in the supabase auth helpers does not require a refresh because it utilizes an <a> instead of <Link> from "next/link". <a> will force the root layout to refresh on navigating while <Link> does not

I believe that signInWithPassword() is not an OAuth redirect method, so I thought the server should be able to access the session immediately. See @thorwebdev's comment regarding OAuth (redirect methods).

If this is not the case, please close my issue.

To Reproduce

Clone this repo or follow the docs to create a Next.js 13 with the app directory. Login in with signInWithPassword() and then navigate using a <Link> to a route protected by middleware /required-session

Expected behavior

After logging on with signInWithPassword(), middleware should be able to detect the session without refreshing the root layout. Middleware cannot auth guard APIs or protected routes unless the user manually refreshes. A benefit of Nextjs.13 app directory, is to avoid refreshes so data is cached.

Screenshot

auth.middleware.mov

System information

  • OS: macOS 13.0.1
  • Browser: Brave, Chrome
  • Version of supabase-js: "@supabase/auth-helpers-nextjs": "^0.5.2" "@supabase/supabase-js": "^2.1.1" next": "13.0.6"
  • Version of Node.js: v18.12.1
@hjaber hjaber added the bug Something isn't working label Dec 2, 2022
@hjaber
Copy link
Author

hjaber commented Dec 3, 2022

This issue was not a bug in either supabase or nextjs.

This is expected behavior of the <Link> component from nextjs.

<Link> prefetches on render so when navigating to a protected route, <Link> already prefetched and determined if you are authenticated or not.

This fix is to prevent prefetching which defeats the purpose of using <Link> and it not recommended.
<Link prefetch={false} />

or the better solution, prevent middleware preflight cache:

response.headers.set(`x-middleware-cache`, `no-cache`);

@hjaber hjaber closed this as completed Dec 3, 2022
@frankspin89
Copy link

@hjaber can you share how you implemented the x-middleware-cache header? My implementation doesn't work:

export async function middleware(req: NextRequest) {
  const res = NextResponse.next();

  res.headers.set("x-middleware-cache", "no-cache");

  // @ts-ignore
  const supabase = createMiddlewareSupabaseClient({ req, res });

  const {
    data: { session }
  } = await supabase.auth.getSession();

  console.log("Session:", session);
  //console.log("Request:", req);
  console.log("Response:", res);

  if (!session && req.nextUrl.pathname.startsWith('/profile')) {

    // Auth condition not met, redirect to home page.
    const redirectUrl = req.nextUrl.clone();
    redirectUrl.pathname = '/';
    redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname);
    return NextResponse.redirect(redirectUrl);
  }


  return res;
}

@hjaber
Copy link
Author

hjaber commented Dec 14, 2022

@hjaber can you share how you implemented the x-middleware-cache header? My implementation doesn't work:

export async function middleware(req: NextRequest) {
  const res = NextResponse.next();

  res.headers.set("x-middleware-cache", "no-cache");

  // @ts-ignore
  const supabase = createMiddlewareSupabaseClient({ req, res });

  const {
    data: { session }
  } = await supabase.auth.getSession();

  console.log("Session:", session);
  //console.log("Request:", req);
  console.log("Response:", res);

  if (!session && req.nextUrl.pathname.startsWith('/profile')) {

    // Auth condition not met, redirect to home page.
    const redirectUrl = req.nextUrl.clone();
    redirectUrl.pathname = '/';
    redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname);
    return NextResponse.redirect(redirectUrl);
  }


  return res;
}

vercel/next.js#43675

No luck either.

I ultimately didn't think it was an elegant solution to rerun middleware on every single route change so I decided not to continue this path.

For now, I reverted back to a provider context until vercel adds read/write cookies with server components. Or a better way to cache the auth in server components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants