javascriptnext.jsfirebase-authenticationnext.js13react-server-components

Firebase Authentication in Nextjs with Server Components


I am trying to learn how to implement authentication with firebase to my nextjs app. First thing we do while using firebase is initialize our firebase with our configuration (apiKey etc.). If i use any firebase function from a client component, it requires this configuration to be sent to client and i think this is something we should never do?

https://firebase.google.com/codelabs/firebase-nextjs#5 But in this tutorial of google they do just that? They prefixed .env variables with NEXT_PUBLIC_ which makes them available to client components? Would a company like google create a wrong tutorial for their product? Is it okay to send my firebase conf. to client?

If not how can i implement this functionality with server components. I think for sign in and sign out, I can call server actions?

The thing I cant do is how to listen for authentication state and render UI according to that(change sign in button to signout button etc.)

lets assume i have server component navbar:

function Navbar() {
  let signedIn = false;
  auth.onAuthStateChanged((authUser) => {
    if (authUser) {
    signedIn = true;
    } 
  });
return (
 signedIn ? <SignOutButton /> : <SignInButton />
 )
}

I cant use state or useEffect on server component and i dont know declaring normal variable like this would be appropriate?


Solution

  • please go through below

    this is how a typical config. file looks like

    import firebase from 'firebase/app';
    import 'firebase/auth';
    
    const firebaseConfig = {
      apiKey: 'YOUR_API_KEY',
      authDomain: 'YOUR_AUTH_DOMAIN',
      projectId: 'YOUR_PROJECT_ID',
      storageBucket: 'YOUR_STORAGE_BUCKET',
      messagingSenderId: 'YOUR_MESSAGING_SENDER_ID',
      appId: 'YOUR_APP_ID',
    };
    
    if (!firebase.apps.length) {
      firebase.initializeApp(firebaseConfig);
    }
    

    you must be worrie about mostely by exposing the API key to public.so read below for that

    ( ref. api-keys#general-info)

    API keys for Firebase are different from typical API keys

    Unlike how API keys are typically used, API keys for Firebase services are not used to control access to backend resources; that can only be done with Firebase Security Rules (to control which users can access resources) and App Check (to control which apps can access resources).

    Usually, you need to fastidiously guard API keys (for example, by using a vault service or setting the keys as environment variables); however, API keys for Firebase services are ok to include in code or checked-in config files.

    Although API keys for Firebase services are safe to include in code, there are a few specific cases when you should enforce limits for your API key; for example, if you're using Firebase ML, Firebase Authentication with the email/password sign-in method, or a billable Google Cloud API. Learn more about these cases later on this page.

    also go through is-it-safe-to-expose-firebase-apikey-to-the-public

    if you are clear about the uses and working of the API keys in your firebase projest then you can follow the rest of implitation as usual

    for example :

    for signInWithGoogle:

    const signInWithGoogle = async () => {
      const provider = new firebase.auth.GoogleAuthProvider();
      await firebase.auth().signInWithPopup(provider);
    };
    

    now for the purpose of making sure user's authentication status(as you highlighted). You can use Subscribe states to authentication changes To subscribe to authentication changes, follow these steps:

    Navigate to the src/components/Header.jsx file. Replace the useUserSession function with the following code:

    function useUserSession(initialUser) {
            // The initialUser comes from the server through a server component
            const [user, setUser] = useState(initialUser);
            const router = useRouter();
    
            useEffect(() => {
                    const unsubscribe = onAuthStateChanged(authUser => {
                            setUser(authUser);
                    });
                    return () => {
                            unsubscribe();
                    };
            }, []);
    
            useEffect(() => {
                    onAuthStateChanged(authUser => {
                            if (user === undefined) return;
                            if (user?.email !== authUser?.email) {
                                    router.refresh();
                            }
                    });
            }, [user]);
    
            return user;
    }
    

    for more details visit ref : firebase-nextjs#5