2022-01-10
3349
#firebase#react
Yusuff Faruq
15074
Jan 10, 2022 â‹… 11 min read

Handling user authentication with Firebase in your React apps

Yusuff Faruq Frontend web developer and anime lover from Nigeria.

Recent posts:

A Guide To The React UseReducer Hook

A guide to the React useReducer Hook

The useReducer React Hook is a good alternative to tools like Redux, Recoil, or MobX.

Ejiro Asiuwhu
Oct 10, 2024 â‹… 13 min read
Using The Built-In SQLite Module In Node.js

Using the built-in SQLite module in Node js

Node.js v22.5.0 introduced a native SQLite module, which is is similar to what other JavaScript runtimes like Deno and Bun already have.

Amazing Enyichi Agu
Oct 10, 2024 â‹… 12 min read
Understanding and supporting zoom behaviors on the web

Understanding and supporting zoom behaviors on the web

Understanding and supporting pinch, text, and browser zoom significantly enhances the user experience. Let’s explore a few ways to do so.

Fimber Elemuwa
Oct 9, 2024 â‹… 7 min read
Comedy and tragedy masks symbolizing Playwright Extra's ability to extend Playwright with customizable plugins for both stealth and interactive browser automation tasks.

Playwright Extra: extending Playwright with plugins

Playwright is a popular framework for automating and testing web applications across multiple browsers in JavaScript, Python, Java, and C#. […]

Antonello Zanini
Oct 8, 2024 â‹… 9 min read
View all posts

51 Replies to "Handling user authentication with Firebase in your React apps"

  1. After creating an account you call generateUserDocument(user, {displayName}}). Should the result of this call be used to update the context? Also, onAuthStateChanged is triggered as soon as you register which calls generateUserDocument(userAuth). How do we now that generateUserDocument(user, {displayName}}) is called after generateUserDocument(userAuth)?

  2. Calling generateUserDocument(user, {displayName}) during account creation writes a new user document to firestore. The data contained in this document (the display name included) are now used to update the user context in onAuthStateChanged.

  3. Thanks for your response. So is the write operation guaranteed to complete before onAuthStateChanged is triggered?

    What if the onAuthChanged completes before the write operation? Wouldn’t we have an outdated user in the context?

  4. So far, this seems to work without problems for me.
    If you do, however, find any problems such as onAuthChanged completing before the write operation, I would be glad to look into it.

  5. i am sorry,
    but you hidden the firebase info in the article

    const firebaseConfig = {
    apiKey: ‘AIzaXXXXXXXXXXXXXXXXXXXXXXX’,
    authDomain: ‘test-XXXX.firebaseapp.com’,
    databaseURL: ‘https://test-XXXXXX.firebaseio.com’,
    projectId: ‘test-XXXX’,
    storageBucket: ‘test-XXXX.appspot.com’,
    messagingSenderId: ‘XXXXXXX’,
    appId: “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”
    };

    but with developer tools i can see the data in plain text

    const firebaseConfig = {
    apiKey: “AIzaSyA9WZB5N6ekNxyN3yGaUwjuBilvXItUv38”,
    authDomain: “fir-auth-article.firebaseapp.com”,
    databaseURL: “https://fir-auth-article.firebaseio.com”,
    projectId: “fir-auth-article”,
    storageBucket: “fir-auth-article.appspot.com”,
    messagingSenderId: “774252759419”,
    appId: “1:774252759419:web:e014ddfa3553a4832a15de”,
    measurementId: “G-77Z5WJ0SET”
    };

    are u sure this tutorial is safe to be taken as an example?

  6. Hi, I just directly downloaded your github repo and changed the API details for firebase.
    I keep getting this error. Any help?
    Unhandled Rejection (FirebaseError): Failed to get document because the client is offline.

  7. Hi, thanks for this super helpful article! I’ve noticed that on page refresh, when the user is signed in, it flashes the authentication page before switching to the profile page. Do you have any tips on a best approach to solve this? Thanks!

    1. I’ve same issue while page refresh after login, login page appears for 1 or 2 second and then route will be changed

  8. Hi, I’ve been trying to render a spinner until the object is loaded but I can’t find a way to do it. Could you give a little more detail on how to implement this? Thank you!

  9. It have the exact same issue as described by Nuur, during the account creation after the createUserWithEmailAndPassword I’m updating the user profile using updateProfile (https://firebase.google.com/docs/reference/js/firebase.User#updateprofile not storing in firestore) but in the meantime the onAuthStateChanged is triggered and so the register page component is unmounted (because i’m routing the /register to / if a user is connected). 2 main issue here : 1) the user state is outdated because onAuthStateChanged is triggered before the complete account creation (missing the displayName) and the 2) can’t catch the error of the 2nd async call (User.updateProfile) because the component is unmounted.

  10. I’m seeing the same as Nuur and Di2pra. Didn’t notice it until I started using the sign in with email and password. Has anyone found a decent workaround?

  11. Amazing tutorial! This helped me set up my own project. Maybe link the repo on top of the article for new readers?
    Huge thanks and have a good day!

  12. I am trying to update the code from React.createClass To extends React.Component – I hit an issue when I convert from ‘const Home = () => {‘ to ‘class Home extends useContext {‘ because of the following lines:

    const user = useContext(UserContext);
    const {photoURL, displayName, email} = user;

    How should I re-format these lines?

    Thank you!

  13. I’m just learning React and this has been an amazing guide. Really got me in the right headspace for using Firebase with React. You even got me learning about Hooks which I hadn’t gotten around to yet, so thanks for that too!

  14. @Faruq – Thanks for the write up. Pretty good information here.

    Just an FYI, in the write up you forget to mention after creating the UserContext/Provider – that you need to go back into your Application.js file and change the line:

    const user = null

    TO

    const user = useContext(UserContext);

    This is an important part of the application logic change, otherwise it will never detect the sign in and will never re-route to Profile page.

  15. Hey @Faruq

    Having issues on the destructuring in the profile page

    here is the error

    TypeError: Cannot destructure property ‘photoURL’ of ‘user’ as it is null.
    Welcome

    const user = useContext(UserContext);
    const {photoURL, displayName, email} = user;
    console.log(user);

    I tried removing the photoURL then got this

    TypeError: Cannot destructure property ‘displayName’ of ‘user’ as it is null.
    wq

    same with third property

    TypeError: Cannot destructure property ’email’ of ‘user’ as it is null.

    If I simply console log user I am getting the userobject properly But cant seem to access any of the properties

    this is my setup

    “dependencies”: {
    “@material-ui/core”: “^4.10.2”,
    “@material-ui/icons”: “^4.9.1”,
    “@material-ui/lab”: “^4.0.0-alpha.56”,
    “@testing-library/jest-dom”: “^4.2.4”,
    “@testing-library/react”: “^9.5.0”,
    “@testing-library/user-event”: “^7.2.1”,
    “firebase”: “^7.15.1”,
    “react”: “^16.13.1”,
    “react-dom”: “^16.13.1”,
    “react-firebase”: “^2.2.8”,
    “react-router-dom”: “^5.2.0”,
    “react-scripts”: “3.4.1”
    },

    Can you tell me whats going wrong

    Thanks for the help

  16. I’m having the same issues as @Mark when it comes to retrieving the props on the profile page, they show up as null. Could you provide any help? The article was great and has been a huge help so far

  17. To get around the issue of the issue of the authOnStateChanged event listener firing before the user document has been written to firestore, I created a separate method named loadUser which through the use of setInterval polls firestore every second and checks to see if the document is written. I set it up to only make 3 attempts after which it stops. When you’ve reached the number of retries or you’ve gotten the full user document you can called clearInterval to stop the polling. This is really a poorly written hack and I’m still looking for a more elegant solution.

    class UserProvider extends React.Component {
    constructor(props) {
    super(props);
    this.state = { currentUser: null, isLoggedIn: false };
    this.loadUser = this.loadUser.bind(this);
    }

    componentDidMount() {
    this.retries = 3;
    this.authListener = auth.onAuthStateChanged(userAuth => {
    if (userAuth) {
    this.intervalId = setInterval(this.loadUser, 1000, userAuth.uid);
    console.log(this.intervalId);
    } else {
    this.setState({ currentUser: null, isLoggedIn: false });
    }
    });
    }

    componentWillUnmount() {
    this.authListener();
    }

    async loadUser(userId) {
    console.log(`Load user called. Number of retries: ${this.retries}`);
    if (this.retries === 1) {
    clearInterval(this.intervalId);
    }
    try {
    const currentUser = await getUserDocument(userId);
    if (currentUser.email) {
    this.setState({ currentUser, isLoggedIn: true });
    clearInterval(this.intervalId);
    }
    } catch (error) {
    console.log(`Error logging the user in: ${error}`);
    clearInterval(this.intervalId);
    } finally {
    this.retries -= 1;
    }
    }

  18. Sir I am facing issue in this tutorial, need a help to solve the issue. Please help me out with the problem, I am stuck with sendResetEmail function in passwordreset component

  19. Thanks for the post, it seems most missed the preface of being somewhat experienced with React. Brilliant explanation for an introduction to authentication within React, Thanks Again!

  20. Hey, Yussuf,
    Your code works like a charm for my project, I adapted it to my code for resseting password in Firebase.
    Thx a lot!

  21. allow read, write: if true; will give everyone access to the database regardless of authorisation. I suggest not doing this.

  22. This is exactly what’s happening to me.
    On registration user gets updated and generateUserDocument called twice.
    The one from onAuthChanged is called first every time and my user being created without the ‘additionalData’.
    Do you have any idea of how to solve this issue?

  23. Hello and thanks for the tutorial. I have a question though. Can I use useAuthState in a redux reducer ? I want to store all my state variables at the same place so is there a way to store user, loading and error in my reducer ? Thanks by advance.

    1. Hi Rico, I had the same issue. For me, this solution worked: I just added the “navigate” hook to the dependency array.

      useEffect(() => {
      if (loading) return;
      if (user) {
      navigate(“/”)
      } else {
      navigate(“/login”)
      }
      }, [user, navigate]);

  24. Another problem which is similar, that is whatever I use google or email login, it shows “An error occurred while fetching user data”, but it still shows as login?

  25. Yusuff,

    This is working great except for one thing. When I refresh the dashboard page after logging in, the screen turns white. Do you know how to fix this?

Leave a Reply