'Getting null returned from getServerSideProps after odd number of times

I am working with next.js and supabase as my stack. I want to know what would cause a user to not be returned from getServerProps. When i log in to my app im ok everything works, but if i continue to log in and out sometimes the user will not be returned from supabase.auth.api.getUserByCookie(req). Im wondering what would cause that because i would have to click login button twice for it log me in properly. I have wired up everything correctly but its seems my ui logic maybe is not getting what it needs to redirect to on successful login from supabase. At this point im not sure what is going on.

Here is my code.

/pages/protected

        import { supabase } from '../utils/supabaseClient';

        export default function protectedPage({ user }) {

            return (
                <div>
                    <p>
                        Welcome { user.email }! {" "}
                    </p>
                    top secret page!
                </div>
            )
        }

        export async function getServerSideProps({ req }) {
            const { user } = await 
             supabase.auth.api.getUserByCookie(req)
       // const { user } = await supabase.auth.api.getUser(req.cookies["sb-access-token"]);
            

            if (!user) {
                console.log('user getServerSideProps ===>', user);
                return { props: {}, redirect: { destination: 
                       '/login', permanent: false } }
            }

            return { props: { user } }
        }

/api/auth

        import { supabase } from "../../utils/supabaseClient";

        export default async function handler(req, res) {
            await supabase.auth.api.setAuthCookie(req, res);
        }

/pages/login

        import { useRouter } from "next/router";
        import { useState } from "react";
        import { useUser } from "../context/user";

        export default function Login() {
            const router = useRouter();
            const { login } = useUser();
            const [email, setEmail] = useState('');
            const [password, setPassword] = useState('');

            const signInUser = async (event) => {
                 event.preventDefault();
                
                const user = await login(event.target.email.value, 
                 event.target.password.value);
                if (user) router.push('/protected');
            };

        return (
            <div className="flex flex-col items-center justify-center">
            <div className="w-full max-w-xs mt-20">
                    <h2 className='text-xl text-blue-700 mb-4 text-center'>Login</h2>
                        <form className='bg-white shadow-md rounded px-8 pb-8 mb-4 py-8' 
                                onSubmit={signInUser}>
                            <div className='mb-4'>
                                <label className='block text-gray-700 text-sm font-bold 
                                    mb-2' htmlFor='email'>
                                    Email
                                </label>
                                <input className='w-full shadow appearance-none border 
                                    rounded py-2 px-3 text-gray-700 leading-tight
                                    focus:outline-none focus:shadow-outline' id='email' 
                                    type='email' placeholder='Email' name="email"
                                    value="[email protected]" onChange={(e) => 
                                    setEmail(e.target.value)}
                                    required />
                            </div>
                            <div className='mb-6'>
                                <label className='block text-gray-700 text-sm font-bold 
                                     mb-2' htmlFor='password'>Password</label>
                                <input className='w-full shadow appearance-none border 
                                     rounded py-2 px-3 text-gray-700 leading-tight
                                     focus:outline-none focus:shadow-outline' 
                                     id='passowrd' type='password' 
                                     placeholder='Password' 
                                     name="password"
                                     required  value="general1az" onChange={(e) => 
                                     setPassword(e.target.value)}/>
                            </div>
                            <button type='submit' className='bg-blue-400 rounded px-4 
                                     mt-4 text-white'>Login</button>
                        </form>
                </div>
            </div>
          );
        }

/context/user

                    import {
            useEffect,
            useState,
            createContext,
            useContext,
        } from 'react'
        import { useRouter } from 'next/router';

        import { supabase } from '../utils/supabaseClient';

        export const UserContext = createContext(null);

        export function UserContextProvider(props) {
            const router = useRouter();

            const [user, setUser] = useState(null);
            const [isLoading, setIsLoading] = useState(true);

            useEffect(() => {
                setUser(supabase.auth.user());

                supabase.auth.onAuthStateChange((event, session) => {
                        // setSession(session);
                        setUser(session?.user);
                        fetch("/api/auth", {
                        method: "POST",
                        headers: new Headers({ "Content-Type": "application/json" }),
                        credentials: "same-origin",
                        body: JSON.stringify({ event, session }),
                        }).then((res) => res.json());
                    });
            }, [])

            const logout = async () => {
                await supabase.auth.signOut();
                setUser(null);
                setIsLoading(true);
                router.push('/')
            }

            const login = async (email, password) => {
                let { user, error } = await supabase.auth.signIn({
                    email,
                    password
                });

                if(error) {
                    console.log('There is an error: ', error);
                    return null;
                }
                
                if(user) {
                    setUser(user);
                }

                return user;
            }

            const signup = async (email, password) => {
                let { user, error } = await supabase.auth.signUp({
                    email,
                    password
                });

                if(error) {
                    console.log('There is an error: ', error);
                    return null;
                }

                
                if (user) {
                    setUser(user);
                }

                return user;
            }

            const value = {
                user,
                signup,
                login,
                logout,
                isLoading,
            };

            return <UserContext.Provider value={value} {...props} />;
        };

        export const useUser = () => useContext(UserContext);

I am sorry if the code is messy i havent refactored it yet just testing out supabase and next.js.



Solution 1:[1]

I solved it! useEffect needs to run every time there is a changed in supabase.auth.onAuthStateChange to stay in sync. Code change useEffect user to useEffect(() => {}) to run every time changes are made.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ZenzMatic