gladly-team / next-firebase-auth

Simple Firebase authentication for all Next.js rendering strategies
https://nfa-example-git-v1x-gladly-team.vercel.app/
MIT License
1.34k stars 291 forks source link

Auth lost on refresh / navigation, but user stays logged in #646

Closed clarencefoy closed 1 year ago

clarencefoy commented 1 year ago

When filing a bug report, please confirm you've done the following:

  1. Have you set onVerifyTokenError and onTokenRefreshError in your config and checked for any helpful errors?

Yes. (edit) -> I think the error further below was thrown by one of these functions, but not sure the error msg helps much

  1. Have you set debug: true in your config and read through server-side and client-side debug logs for any helpful messages?

Is this in the 'init' function, or in another config? I have not done this, but if you let me know where I can do this, I will

  1. Have you tried the example app with your own Firebase credentials?

I have tried, but couldn't install the app due to React 18 and firebase web-ui being incompatible. I then forced install to override dependency issues. Upon starting the app, it seemed like there was no way to signup users to Firebase, so I couldn't test login. I entered wrong details and that sort of mock-logged me in, but obviously without there being a real user in Firebase, I couldn't make it work. I am also on Next 13 instead of 12, so that may create differences?

  1. Have you read through the troubleshooting Q&A?

Reading through this, I have made sure of the following:

image

Describe the bug

This app has two types of data at the moment: Users and businesses. Users are able to add businesses. I am able to login using NFA, can get the user profile and details and businesses. This is done by accessing the collection 'businesses' in Firestore:

image

When navigating away and back, or refreshing, the following error is shown:

image

Naturally, I checked my Firestore rules:

image

From what I can tell, an authenticated user should be able to access any docs. And of course it works immediately after login. It just stops working on refresh.

What is particularly odd is that when navigating away and back to the app, the user's logged-in state is remembered. As in, I am correctly re-authenticated when accessing the app again. It's just that getting 'businesses' suddenly fails. So, somehow on refresh or after navigating away and back, Firebase rejects authentication just for the collection request.

Versions

next-firebase-auth version: ^1.0.0-canary.19 Firebase JS SDK: ^9.20.0 Next.js: 13.2.4

To Reproduce Steps to reproduce the behavior: I wouldn't expect you to install my app, but perhaps I can show you some code:

Initialising like this:

import { init } from "next-firebase-auth";
import { initializeApp } from "firebase/app";

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: "business-guides.appspot.com",
  messagingSenderId: "3411906151",
  appId: "1:3411906151:web:2981b4bf6bae10566a8ec2",
  measurementId: "G-BY37ZMMBCY",
};

const initAuth = () => {
  init({
    authPageURL: "/",
    appPageURL: "/",
    loginAPIEndpoint: "/api/login",
    logoutAPIEndpoint: "/api/logout",
    onLoginRequestError: (err) => {
      console.error("Login request error: ", err);
    },
    onLogoutRequestError: (err) => {
      console.error("Logout request error: ", err);
    },
    //firebaseAuthEmulatorHost: "localhost:9099",
    firebaseAdminInitConfig: {
      credential: {
        projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
        clientEmail: process.env.FIREBASE_SERVICE_ACCOUNT,
        // The private key must not be accessible on the client side.
        privateKey: process.env.FIREBASE_PRIVATE_KEY,
      },
      databaseURL: "",
    },
    // Use application default credentials (takes precedence over firebaseAdminInitConfig if set)
    // useFirebaseAdminDefaultCredential: true,
    firebaseClientInitConfig: {
      apiKey: process.env.NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY,
      authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
      databaseURL: "",
      projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
    },
    cookies: {
      name: "BusinessDirectory", // required
      // Keys are required unless you set `signed` to `false`.
      // The keys cannot be accessible on the client side.
      keys: [
        process.env.COOKIE_SECRET_CURRENT,
        process.env.COOKIE_SECRET_PREVIOUS,
      ],
      httpOnly: true,
      maxAge: 12 * 60 * 60 * 24 * 1000, // twelve days
      overwrite: true,
      path: "/",
      sameSite: "strict",
      secure: process.env.SECURE === 1, // set this to false in local (non-HTTPS) development
      signed: true,
    },
    onVerifyTokenError: (err) => {
      console.error(err);
    },
    onTokenRefreshError: (err) => {
      console.error(err);
    },
  });
  try {
    const app = initializeApp(firebaseConfig);
  } catch (err) {
    console.error(err);
  }
};

export default initAuth;

I then try to fetch a user's businesses:

import * as React from "react";
import { getApp } from "firebase/app";
import { getFirestore, collection, onSnapshot } from "firebase/firestore";
import { Container, User, Button } from "@nextui-org/react";
import {
  AuthAction,
  useAuthUser,
  withAuthUser,
  withAuthUserTokenSSR,
} from "next-firebase-auth";

const MyProfilePage = () => {
  const [businesses, setBusinesses] = React.useState([]);
  const AuthUser = useAuthUser();

  React.useEffect(() => {
    return onSnapshot(
      collection(getFirestore(getApp()), "businesses"),
      (snap) => {
        if (!snap) {
          console.log("No such document!");
          return;
        }
        setBusinesses(snap.docs.map((doc) => ({ ...doc.data(), key: doc.id })));
      }
    );
  }, []);

  return (
    <Container direction="column">
      {AuthUser ? (
        <React.Fragment>
          <User
            src={
              AuthUser.photoURL
                ? AuthUser.photoURL
                : "https://i.pravatar.cc/150?u=a042581f4e29026704d"
            }
            name={AuthUser.displayName}
          />
          <h2>Email: {AuthUser.email}</h2>{" "}
        </React.Fragment>
      ) : null}

      <h1>Your Businesses</h1>
      {businesses &&
        businesses.map((business) => (
          <React.Fragment key={business.id}>
            <div>ID: {business.id}</div>
            <div>Name: {business.name}</div>
            <div>ShortDescription: {business.shortDescription}</div>
            <div>PhoneNumber: {business.phoneNumber}</div>
            <div>Email: {business.email}</div>
            <div>Website: {business.website}</div>
            <div>Facebook: {business.facebook}</div>
            <div>Instagram: {business.instagram}</div>
            <div>Twitter: {business.twitter}</div>
            <div>Youtube: {business.youtube}</div>
            <div>LongDescription: {business.longDescription}</div>
            <div>OpeningTimes: {business.openingTimes}</div>
            <div>Tags: {business.tags}</div>
            <div>Category: {business.category}</div>
            <div>Address: {business.address}</div>
          </React.Fragment>
        ))}
    </Container>
  );
};
const MyLoader = () => <div>Loading...</div>;

export const getServerSideProps = withAuthUserTokenSSR({
  whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,
  LoaderComponent: MyLoader,
})();

export default withAuthUser()(MyProfilePage);

Expected behavior I would like to be able to navigate away from my user's profile page and come back and still be able to get the user's businesses from the 'businesses' collection in my Firestore. If auth never worked, or I got other errors, I wouldn't be opening an issue, but because it seems that auth is 'forgotten' in betwen navigations or refreshes, I wondered whether it's a bug. I'd of course much prefer if this was an issue on my side...

Debug and error logs (edit) -> I have posted the error above, I think it is thrown by these functions:

image

Additional context I have no more information :)

barbrick commented 8 months ago

@clarencefoy did you resolve this issue? It's occurring for me after updating Next and next-firebase-auth, but was previously working as expected.