How to redirect using `getServerSideProps` with props in Next.js?

Viewed 51

After a user signs in, I use router.push() to redirect the user to their profile page. I am using getServerSideProps() for authentication right now. When the redirect happens, the props don't seem to be fetched and I have to refresh the browser myself to call gSSR. Is this behavior normal or is there a way to fix it?

Demonstration - Updated

login.js

import {useRouter} from 'next/router';

export default function Login({user}) {
  const router = useRouter();

  // invoked on submission
  async function submitLoginForm(email, password) {
    const user = await signIn(email, password)
    const username = await getUsernameFromDB(user);
    router.push("/" + username);
  }

  return ( ... );
}

export async function getServerSideProps({req}) {
  const user = await getUserFromCookie(req);
  if(user === null) {
    return {
      props: {}
    }
  }
  return {
    redirect: {
      destination: `/${user.username}`,
      permanent: false
    }
  }
}

[username].js

export default function Profile({user, isUser}) {
  // Use isUser to render different interface.
  return ( ... );
}

export async function getServerSideProps({params, req}) {
  // The username of the path.
  const profileUsername = params.username
  // Current user.
  const user = await getUserFromCookie(req);
  ...
  if(user !== null) {
    return {
      props: { 
        user: user, 
        isUser: user !== null && profileUsername === user.username
      }
    }
  }
  return {
    notFound: true
  }
}

The cookie is set in the _app.js using the Supabase auth sdk.

function MyApp({Component, pageProps}) {
  supabase.auth.onAuthStateChange( ( event, session ) => {
    fetch( "/api/auth", {
      method: "POST",
      headers: new Headers( { "Content-Type": "application/json" } ),
      credentials: "same-origin",
      body: JSON.stringify( { event, session } ),
    } );
  } );

  return (
    <Component {...pageProps} />
  );
}
1 Answers

I would recommend that you update your _app.js like that:

import { useEffect } from 'react';

function MyApp({ Component, pageProps }) {
  
  // make sure to run this code only once per application lifetime
  useEffect(() => {
    // might return an unsubscribe handler
    return supabase.auth.onAuthStateChange(( event, session ) => {
      fetch( "/api/auth", {
        method: "POST",
        headers: new Headers( { "Content-Type": "application/json" } ),
        credentials: "same-origin",
        body: JSON.stringify( { event, session } ),
      });
    });
  }, []);
  

  return <Component {...pageProps} />;
}

Also, please make clear what is happening. E.g. my current expectation:

  • Not authenticated user opens the "/login" page
  • He does some login against a backend, that sets a cookie value with user information
  • Then router.push("/" + username); is called
  • But the problem now: On page "/foo" he sees now the Not-Found page instead of the user profile
    • Only after page reload, you see the profile page correctly

If the above is correct, then it is possible the following line is not correctly awaiting the cookie to be persisted before the navigation happens:

const user = await signIn(email, password)

It could be that some internal promise is not correctly chained/awaited.

As an recommendation, I would log to the console the current cookie value before calling the router.push to see if the cookie was already saved.

Related