I am using firebase auth for my web application. It seems that after a user has signed in, their session is only persisted for about an hour, then after they come back to the website or reload the page, they will be logged out and need to sign in again. They are not signing out manually but rather being signed out after some time interval. Is there a way to keep users signed-in indefinitely, until they request to be signed out?
Here is the code:
/********************************************************************************
*** Description: A hook which listens for Firebase changes.
***
*** https://blog.logrocket.com/implementing-authentication-in-next-js-with-firebase/
********************************************************************************/
//==============================================================================
// IMPORTS
//==============================================================================
/* Yarn */
import { useState, useEffect } from 'react';
import {
getAuth,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
sendPasswordResetEmail,
updateProfile
} from "firebase/auth";
import type { User } from "firebase/auth";
/* Personal */
import Firebase from '.';
//==============================================================================
// HELPER FUNCTIONS
//==============================================================================
/**
* Returns necessary information from a firebase user.
*
* @param user Firebase User.
* @returns An object containing the user's uid, email, and displayName.
*/
const formatAuthUser = (user: User) => ({
uid: user.uid,
email: user.email,
displayName: user.displayName
});
//==============================================================================
// EXPORTS
//==============================================================================
export default function useFirebaseAuth() {
const [authUser, setAuthUser] = useState(null);
const [loading, setLoading] = useState(true);
/**
* Callback function when authentication state changes.
*
* @param authState User's state.
* @returns
*/
const authStateChanged = async (authState: User) => {
if (!authState) {
setAuthUser(null);
setLoading(false);
return;
}
setLoading(true);
const formattedUser = formatAuthUser(authState);
setAuthUser(formattedUser);
setLoading(false);
};
/**
* Clear user.
*/
const clear = () => {
setAuthUser(null);
setLoading(true);
};
/**
* Sign in with email and password.
*
* @param email User's email.
* @param password User's password.
* @returns Promise of the UserCredentials.
*/
const signInWithEmailAndPasswordWrapper = (email: string, password: string) =>
signInWithEmailAndPassword(getAuth(Firebase), email, password);
/**
* Create a new account.
*
* @param email User's email.
* @param password User's password
* @returns Promise of the UserCredentials.
*/
const createUserWithEmailAndPasswordWrapper = (email: string, password: string) =>
createUserWithEmailAndPassword(getAuth(Firebase), email, password);
/**
* Updates a user's display name.
*
* @param displayName Unique username.
* @returns
*/
const updateUserDisplayName = (displayName: string) => {
setLoading(true);
const currentUser = getAuth(Firebase).currentUser;
updateProfile(currentUser, { displayName });
const formattedUser = {
uid: currentUser.uid,
email: currentUser.email,
displayName
};
setAuthUser(formattedUser);
setLoading(false);
}
/**
* Sends a password reset email.
*
* @param email Email to send password reset to.
* @returns
*/
const sendPasswordResetEmailWrapper = (email: string) =>
sendPasswordResetEmail(getAuth(Firebase), email)
/**
* Remove authentication.
*
* @returns
*/
const signOut = () => getAuth(Firebase).signOut().then(clear);
// Listen for Firebase state change.
useEffect(() => {
const unsubscribe = getAuth(Firebase).onAuthStateChanged(authStateChanged);
return () => unsubscribe();
}, []);
return {
authUser,
loading,
signInWithEmailAndPasswordWrapper,
createUserWithEmailAndPasswordWrapper,
updateUserDisplayName,
sendPasswordResetEmailWrapper,
signOut
};
}
This is used within context to access the auth state anywhere in the application:
/********************************************************************************
*** Description: Creates a wrapper to access auth variables in any component.
***
*** https://blog.logrocket.com/implementing-authentication-in-next-js-with-firebase/
********************************************************************************/
//==============================================================================
// IMPORTS
//==============================================================================
/* Yarn */
import { createContext, useContext } from 'react'
/* Personal */
import useFirebaseAuth from './useFirebaseAuth';
//==============================================================================
// CREATE CONTEXT
//==============================================================================
const authUserContext = createContext({
authUser: null,
loading: true,
signInWithEmailAndPasswordWrapper: (email: string, password: string) => null,
createUserWithEmailAndPasswordWrapper: (email: string, password: string) => null,
updateUserDisplayName: (displayName: string) => null,
sendPasswordResetEmailWrapper: (email: string) => null,
signOut: () => null
});
//==============================================================================
// EXPORTS
//==============================================================================
export function AuthUserProvider({ children }) {
const auth = useFirebaseAuth();
return <authUserContext.Provider value={auth}>{children}</authUserContext.Provider>;
}
/**
* Custom hook to use the authUserContext.
*/
export const useAuth = () => useContext(authUserContext);
The entire application is wrapped with the AuthUserProvider.
You need both the Token Service API and Identity Toolkit API enabled in order to persist the user's login status. I originally only had the Identity Toolkit API, so when the requesting a new token each hour, it would fail and then the user would be logged out.