Jophin Joseph
Jophin Joseph

Reputation: 2953

How do I detect if a user is already logged in Firebase?

I'm using the firebase node api in my javascript files for Google login.

firebase.initializeApp(config);
let provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider);

This works fine and the user is able to login with his Google credentials. When the user visits the page again, the popup opens again but since he has already logged in, the popup closes without requiring any interaction from the user. Is there any way to check if there is already a logged in user before prompting the popup?

Upvotes: 165

Views: 229582

Answers (15)

easyScript
easyScript

Reputation: 633

I use react and react-router-dom with loader function, after refreshing page my loader can't load data from firestore because firebase app need a litle time to initialize. I find easy solution. I set auth method before checking is user logged in and it's works. Again, you need to wait firebase app to settle and this auth method do just that it wait app to initialize. Here my solution, it's so simple:

    export const getContacts = async () => {
        await auth.authStateReady()
        const currentUser = auth.currentUser

        if (!currentUser) return false
       // rest of code ...
    }

await auth.authStateReady() is promise and it will wait to resolve with user or not (if user isn't logged in). So simple, it took me 6 hours to find this method.

Upvotes: 11

Luke Vo
Luke Vo

Reputation: 20798

I was skeptical of the other answer because the name onAuthStateChanged confuses me. I assumed it only work if a user has logged in. This is not the case, when the user is new, onAuthStateChanged is still called (with null as its parameter, NOT undefined).

This is a Promise-based code to get a user if they logged in before:

class AccountService {

    #auth: any;
    #initUserLoaded = false;
    #userCallback?: (user: any) => void;

    constructor() {
        // Other code to initialize Firebase

        fbAuth.onAuthStateChanged(
            this.#auth,
            (user: FbUser) => void this.#onUserChanged(user));
    }

    #onUserChanged(user: any) {
        this.#initUserLoaded = true;

        const cb = this.#userCallback;
        if (cb) {
            this.#userCallback = undefined;
            cb(user);            
        }
    }

    async #getCurrentUserAsync(): Promise<any | undefined> {
        let result = this.#auth.currentUser;
        if (result || this.#initUserLoaded) { return result; }

        result = await new Promise<any>(r => {
            this.#userCallback = r;
        }),
        this.#userCallback = undefined;

        return result ?? undefined; // Convert null to undefined
    }

}

Upvotes: 0

Jmndao
Jmndao

Reputation: 1

You can as well use a use-effect hook in a context to check if the user is authenticated per page (when the user navigates to a page). However, make sure to not include the auth page.

  React.useEffect(() => {
    if (router.asPath !== "/auth") {
      onAuthStateChanged(auth, (user) => {
        if (!user) {
          window.location.href = "/auth";
        }
      });
    }
  }, [router]);

Here I was using nextJS but it's pretty much the same with just reactJS

Upvotes: 0

Salim Ensi
Salim Ensi

Reputation: 1

For the firebase v9.8.1 and angular v13.3.5, I'm not using AngularFire, then I used this service that works well.

@Injectable({providedIn: 'root'})
export class IsAuthenticatedGuard implements CanActivate {

  canActivate(): Promise<boolean> {
    return new Promise(resolve =>
      onAuthStateChanged(getAuth(),
        user => resolve(!!user),
        _ => resolve(false)));
  }

}

Upvotes: 0

Ahmet Şimşek
Ahmet Şimşek

Reputation: 1541

usage example with latest library version

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

const firebaseConfig = {
  ...
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);

onAuthStateChanged(auth, user => {
  if (user) {
    // User is signed in.
  } else {
    // No user is signed in.
  }
})

Upvotes: 5

Jonathan
Jonathan

Reputation: 4709

There are technically 3 possibilities with promises:

// 1) best option, as it waits on user...

const isLoggedIn: any = await new Promise((resolve: any, reject: any) =>
this.afa.onAuthStateChanged((user: any) =>
  resolve(user), (e: any) => reject(e)));

console.log(isLoggedIn);

// 2) may experience logging out state problems...

const isLoggedIn2 = await this.afa.authState.pipe(first()).toPromise();

console.log(isLoggedIn2);

// 3) technically has a 3rd option 'unknown' before user is loaded...

const isLoggedIn3 = await this.afa.currentUser;

console.log(isLoggedIn3);


// then do something like (depending on your needs) with 1, 2, or 3:

if (!!isLoggedIn) {
  // logged in
}

Also note, the example is angular, but you can replace this.afa with firebase.auth()

Upvotes: 2

Ben Winding
Ben Winding

Reputation: 11837

This works:

async function IsLoggedIn(): Promise<boolean> {
  try {
    await new Promise((resolve, reject) =>
      app.auth().onAuthStateChanged(
        user => {
          if (user) {
            // User is signed in.
            resolve(user)
          } else {
            // No user is signed in.
            reject('no user logged in')
          }
        },
        // Prevent console error
        error => reject(error)
      )
    )
    return true
  } catch (error) {
    return false
  }
}

Upvotes: 9

Daniel
Daniel

Reputation: 7

First import the following

import Firebase
import FirebaseAuth

Then

    // Check if logged in
    if (Auth.auth().currentUser != null) {
      // User is logged in   
    }else{
      // User is not logged in
    }

Upvotes: -9

Qwerty
Qwerty

Reputation: 32058

It is not possible to tell whether a user will be signed when a page starts loading, there is a work around though.

You can memorize last auth state to localStorage to persist it between sessions and between tabs.

Then, when page starts loading, you can optimistically assume the user will be re-signed in automatically and postpone the dialog until you can be sure (ie after onAuthStateChanged fires). Otherwise, if the localStorage key is empty, you can show the dialog right away.

The firebase onAuthStateChanged event will fire roughly 2 seconds after a page load.

// User signed out in previous session, show dialog immediately because there will be no auto-login
if (!localStorage.getItem('myPage.expectSignIn')) showDialog() // or redirect to sign-in page

firebase.auth().onAuthStateChanged(user => {
  if (user) {
    // User just signed in, we should not display dialog next time because of firebase auto-login
    localStorage.setItem('myPage.expectSignIn', '1')
  } else {
    // User just signed-out or auto-login failed, we will show sign-in form immediately the next time he loads the page
    localStorage.removeItem('myPage.expectSignIn')

    // Here implement logic to trigger the login dialog or redirect to sign-in page, if necessary. Don't redirect if dialog is already visible.
    // e.g. showDialog()
  }
})



I am using this with React and react-router. I put the code above into componentDidMount of my App root component. There, in the render, I have some PrivateRoutes

<Router>
  <Switch>
    <PrivateRoute
      exact path={routes.DASHBOARD}
      component={pages.Dashboard}
    />
...

And this is how my PrivateRoute is implemented:

export default function PrivateRoute(props) {
  return firebase.auth().currentUser != null
    ? <Route {...props}/>
    : localStorage.getItem('myPage.expectSignIn')
      // if user is expected to sign in automatically, display Spinner, otherwise redirect to login page.
      ? <Spinner centered size={400}/>
      : (
        <>
          Redirecting to sign in page.
          { location.replace(`/login?from=${props.path}`) }
        </>
      )
}

    // Using router Redirect instead of location.replace
    // <Redirect
    //   from={props.path}
    //   to={{pathname: routes.SIGN_IN, state: {from: props.path}}}
    // />

Upvotes: 52

maudulus
maudulus

Reputation: 11045

If you are allowing anonymous users as well as those logged in with email you can use firebase.auth().currentUser.isAnonymous, which will return either true or false.

Upvotes: 3

ravish.hacker
ravish.hacker

Reputation: 1183

One another way is to use the same thing what firebase uses.

For example when user logs in, firebase stores below details in local storage. When user comes back to the page, firebase uses the same method to identify if user should be logged in automatically.

enter image description here

ATTN: As this is neither listed or recommended by firebase. You can call this method un-official way of doing this. Which means later if firebase changes their inner working, this method may not work. Or in short. Use at your own risk! :)

Upvotes: 9

Daniel Vukasovich
Daniel Vukasovich

Reputation: 1742

There's no need to use onAuthStateChanged() function in this scenario.

You can easily detect if the user is logged or not by executing:

var user = firebase.auth().currentUser;

For those who face the "returning null" issue, it's just because you are not waiting for the firebase call to complete.

Let's suppose you perform the login action on Page A and then you invoke Page B, on Page B you can call the following JS code to test the expected behavior:

  var config = {
    apiKey: "....",
    authDomain: "...",
    databaseURL: "...",
    projectId: "..",
    storageBucket: "..",
    messagingSenderId: ".."
  };
  firebase.initializeApp(config);

    $( document ).ready(function() {
        console.log( "testing.." );
        var user = firebase.auth().currentUser;
        console.log(user);
    });

If the user is logged then "var user" will contain the expected JSON payload, if not, then it will be just "null"

And that's all you need.

Regards

Upvotes: 30

Daniel Passos
Daniel Passos

Reputation: 1416

You can also check if there is a currentUser

var user = firebase.auth().currentUser;

if (user) {
  // User is signed in.
} else {
  // No user is signed in.
}

Upvotes: 118

bojeil
bojeil

Reputation: 30868

https://firebase.google.com/docs/auth/web/manage-users

You have to add an auth state change observer.

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

Upvotes: 193

muetzerich
muetzerich

Reputation: 5720

use Firebase.getAuth(). It returns the current state of the Firebase client. Otherwise the return value is nullHere are the docs: https://www.firebase.com/docs/web/api/firebase/getauth.html

Upvotes: 1

Related Questions