27

I have an application built in firebase and angular, and am wanting to be able to keep users logged in after refreshing the page. Right now I have a login screen with two basic input fields which bind to a controller

    this.email = "";
    this.pass = "";
    this.emessage = "";

    this.loginUser = function() {
        ref.authWithPassword({
            email: this.email,
            password: this.pass
        }, function(error, authData) {
            if (error) {
                console.log("Login Failed!", error);
                this.emessage = error.message;
                $scope.$apply();
            } else {
                dataStorage.uid = authData.uid;
                $location.path('/projects');
                $scope.$apply(); 
            }
        }.bind(this));
    }

This is all fine and dandy and it works, but when the user refreshes the page they are logged back out. Is there some way to, when the controller loads, see if the user is already logged in and auto-redirect? Thanks!

Justin Haddock
  • 301
  • 1
  • 3
  • 9

6 Answers6

29

The code you now have handles the case where the user logs on. To handle cases where the user has already logged, you use theonAuthStateChanged method:

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
  } else {
    // User is not signed in.
  }
});

Typically you only want to show the log on button in the else of this function.

In the newer (v9 and up) modular SDKs, that'd be:

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth();
onAuthStateChanged(auth, (user) => {
  if (user) {
    // User is signed in.
    // ...
  } else {
    // User is not signed in.
    // ...
  }
});

Also see the documentation on firebase.auth.Auth and getting the currently signed in user.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • You're welcome. I used to overlook this one until recently and get into all kinds of problems trying to hide my login button, so appreciate the chance to get the word out about how trivial this is *once you know how*. – Frank van Puffelen Aug 27 '15 at 18:55
  • 4
    It looks like the `onAuth` has been deprecated. See https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged – fodma1 Sep 23 '17 at 13:09
  • @FrankvanPuffelen I'm using `onAuthStateChanged` and it doesn't work so well as when I refresh, my app shows "logged out state" like a login button etc before the app kicks in and then shows the correct stuff. should I store stuff locally or cookies or something to make this process seem smoother? – Red Baron May 12 '20 at 20:36
  • Storing a local (preferably synchronous) value is the only way I know to make this faster. Just keep in mind that your local "they are logged in" value *may* be wrong, and ensure you in that case send them back to the sign-in screen. – Frank van Puffelen May 12 '20 at 21:25
12

As mentioned in a comment, the accepted answer no longer works. The current way of checking if a user is logged in is

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
  }
});

(from https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged)

mflodin
  • 1,093
  • 1
  • 12
  • 22
4

I have the challenge that my web app has public pages with protected features. With the following code, the user always gets loaded via Firebase SDK before anything else (if logged in). But also gets redirected to the login page, if the page requires authentication. This work fine with page reloads.

Router.beforeEach((to, from, next) => {

  // If route required authentication
  if (to.matched.some(record => record.meta.requiresAuth)) {

    // Load user
    firebase.auth().onAuthStateChanged(user => {

      // If user obj does not exist --> redirect to login page
      if (!user) {
        next({ name: 'login' });
      } else {
        store.commit("user/SET_USER", user);
        user.getIdToken().then(token => {
          store.commit("user/SET_TOKEN", token)
        });

        next();
      }
    });
  } else {

    // Path does not required auth - Still we check the user
    firebase.auth().onAuthStateChanged(user => {

      // If user exist (is logged in) --> store in state.
      if (user) {  
        store.commit("user/SET_USER", user);
        user.getIdToken().then(token => {
          store.commit("user/SET_TOKEN", token)
        });
        next();

      } else {
        next();
      }
    });
  }
})
segli
  • 230
  • 2
  • 6
  • hey, it would really help if you could provide more info about the code itself, like which file are you writing the code for, etc. – roshnet May 29 '20 at 00:22
3

For any ReactJS users, here's a simple Hook that I have created based on the answers provided in this thread which redirects the user to login route if the current user is not loggedIn.

import { useEffect } from 'react';
import * as firebase from 'firebase';
import { useHistory } from 'react-router-dom';

export default function useProtectedRoute() {
  const history = useHistory();

  useEffect(() => {
    firebase.auth().onAuthStateChanged(function(user) {
      if (!user) {
        console.error(
          'Access to protected route denied, redirecting to login...'
        );
        history.push('/auth/login');
      }
    });
  }, [history]);
}

You just need to import this hook and run inside any component that you don't want to render unless the user is logged in.

Example:

import React from 'react';
import useProtectedRoute from 'hooks/useProtectedRoute';

export default function UserDetailsComponent() {
  useProtectedRoute();
  return <div>This is only visible when user is logged in</div>;
}
Raushan
  • 93
  • 6
0

If you are using Angular 4 you can use AngularFire2 - Official Firebase Integration.

I have a AuthService that wraps AngularFire2. I just retrieve AuthSession in Service's constructor and use when I need it. Example:

@Injectable()
export class AuthenticationService {

    private authState: any;

    constructor(public afAuth: AngularFireAuth) {
        this.afAuth.authState.subscribe((auth) => {
          this.authState = auth
        });
    }

    get user(): any {
        return this.authenticated ? this.authState : null;
    }
}

Full authentication service code here Full Angular 4 with Firebase example here

Makah
  • 4,435
  • 3
  • 47
  • 68
0

Other option sessionStorage

see here:

Angular Firebase auth, how to check if user is logged in to hide login link from navigation?

ztvmark
  • 1,319
  • 15
  • 11