Auth lost on refresh / navigation, but user stays logged in
Closed this issue · 1 comments
When filing a bug report, please confirm you've done the following:
- Have you set
onVerifyTokenError
andonTokenRefreshError
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
- 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
- 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?
- Have you read through the troubleshooting Q&A?
Reading through this, I have made sure of the following:
- The cookies are there and secure = false, as this is http-only localhost:
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:
When navigating away and back, or refreshing, the following error is shown:
Naturally, I checked my Firestore rules:
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:
Additional context
I have no more information :)
@clarencefoy did you resolve this issue? It's occurring for me after updating Next and next-firebase-auth, but was previously working as expected.