I have managed to setup a custom login system using Firebase. The user enters email/password and is redirected to the main page(which is private). I am having issue with onAuthStateChanged after logging in. When I check the auth state after logging into the main page, i get invalid user (null). The firebase dashboard shows I have logged in successfully but onAuthStateChanged is the opposite.
I am trying to check if a user is logged in to my html pages, if not I want to redirect them to the login page. I like how the authentication works in firebase but I need to protect my html pages not my divs (which is what the vast majority of firebase auth tutorials show).
If anyone has an easier way to password protect a web directory that looks nicer than HTaccess, please advise (I am not crazy about using wordpress for password protection, but its an option). Otherwise, I guess I will have to do this in PHP. Thanks in advance!
(function () {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
console.log(user);
console.log('A user is logged in.');
} else {
// No user is signed in.
console.log('Invalid user. Redirecting to root.');
window.location.replace('../index.html');
}
});
})();
If you navigate to a new page, Firebase will have to initialize again. As part of that it will try to restore the user's authentication state, but this requires a call to the server which takes time.
For that reason the onAuthStateChanged listener will initially fire with null as the current user (and auth.currentUser is set to null). Then once the user is signed in, the listener fires again with the user object for that user.
If you want to detect this initial state, you can either store some token value in the browser's local storage that you can check for yourself on the new page, or you could set a time-out for when you expect the user to be re-signed in and only then navigate away to the index.html page.
Related
I am building a login page in my React app using firebase (sign in with google redirect the user method)
and it is working but it takes almost two seconds for firebase to get the current user, which is not the best for UX.
here is the code
componentDidMount(){
console.log(Date.now());
const auth = getAuth();
this.authListener = onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in
console.log(Date.now());
this.props.dispatch(addUserAction(user.email))
}
else {
// User is signed out
this.props.dispatch(addUserAction(null))
}
});
}
what i get in my console is that the difference of time is 1768 milliseconds which is almost 2 seconds,
am i doing something wrong ?
the console is showing the difference of time as 2 seconds
When you restart the app/reload the page, Firebase automatically restores the user's authentication state based on the information it stored in local storage when the user first signed in. For this it does make a call to the server though, to check whether the credentials are still valid - and for example to ensure the account hasn't been disabled. It's likely that this call is what is taking time in your use-case.
A common trick is to make your own determination on whether the server-check is likely to succeed based on only client-side information. For this, store an extra value in local storage when the user signs in successfully, say isAuthenticated. Now when you reload the page/app, you an read this value from local storage, and then the user was previously authenticated, assume that they will be authenticated again.
The assumption may be wrong of course, so you'll have to handle that scenario too in your code.
Also see this talk Architecting Mobile Web Apps, where Michael Bleigh talks about the technique.
I am having a react application with firebase as authentication. My authentication code is below
await firebase.auth().onAuthStateChanged((user) => {
if (user) {
props.setUser(user); //setting the user if login/register happens
history.push(`/admin/dashboard`);
console.log("user",user)
} else {
props.setUser(null); //blocks the user to get into the app if he/she is not logged in
history.push("/");
}
});
So, when user logs in..he will be navigated to /admin/dashboard. suppose when am in /admin/home and when i refresh the page, it goes again to admin/dashboard which shouldn't happen. so I tried
history.push(${props.location.pathname}); it works correctly after the refresh, it stays on the same page when the application is logged in. but when I restart the server again when I try to log in, it says no redirect url is specified. Got stuck on this for a long time.. Any help is welcome.Thanks
What your code does is check if the user is logged in and only let the user access the data if so.
You should do that in the fireabse rules (= serverside) as this is way more secure.
You didn't provide the kind of FirebaseDB you are using. So assuming you use the Realtime Database here are some according rules:
{
“rules”: {
“.read”: “auth != null”,
“.write”: “auth != null”
}
}
You should maybe check the rules before deploying your app, because now every authenticated user can change/add/delete data, but you get the point. This does exactly what you want so you won't even need to perform a check in your ReactJS App. Firebase will automatically deny unauthenticated users the access to the database.
Btw: You should try to implement security relevant things in the Firebase Rules. Ideally you want your rules to be written in a way that you don't need to perform any validation inside your ReactJS app. Firebase rules can get quite complex. I experienced that myself when writing a chat app with chatrooms and everything. But it is definitly worth the effort if your app is more secure after.
I'm working with Firebase in JavaScript.
I use the onAuthStateChanged function to check if the user is logged in, and then redirect to the appropriate html page.
auth.onAuthStateChanged((user) => {
if(user) {
// Logged in
console.log("logged in!");
window.location.href = "dashboard.html";
fetchFromDB();
} else {
console.log("Logged out!");
//window.location.href = "index.html";
}
});
However, it keeps refreshing the page constantly like it's in some infinite loop. I'm not sure what to do here.
Help will be appreciated a lot :)
When the page loads, Firebase starts restoring the signed in user from the local storage of your browser. This requires a call to the server (a.o. to see if the account has been deleted/disabled), which takes some time.
So initially your onAuthStateChanged gets called with null as there is no current user. Then when the authentication state is restored the listener gets called again with the user profile.
My guess it that you're taking some action in the initial null (like redirecting to index.html), and that target page then redirect back to dashboard.html when it gets the user profile.
It's easiest to work with Firebase in a single-page application, as you'd have only a single page load in that case. But if you have multiple pages, you'll need to write code that waits for the authentication state to settle.
Some common ways that I know of:
Ignore the initial null that your onAuthStateChanged callback gets. But keep in mind that the user state may not be restorable in which case the null is all you get, so you may need to act on that after a while.
Design your flow so that you end up in the right spot. This may only work in a single-page application, but I use this one most often: when the page loads (and the user is null), I show a log-in screen. Then when the user profile is restored I navigate to the dashboard. This means that users may briefly see the login screen, but I don't find this too distracting. If you do, read on...
You can store a value in local storage yourself when the user is signed in. Then on a page reload, you can check that value and if it exists: assume that the restore of their auth state will succeed, and show the dashboard first. If the sign-in fails, you can then redirect back to the login screen after a timeout. So this inverts the path of #2, and requires quite some work, but removes the temporary login screen for your returning users.
here, If you are working with react this might work.
useEffect(() => {
onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
console.log("user Changed");
})}, [])
onAuthStateChanged runs everytime component is re-render so useEffect will help in this case.
I have a PWA app where one of the options you have to sign-in is Facebook, everything goes well and if you're in the browser the login works really well. The problem happens when you add the website to your mobile and it opens in PWA and you click log-in from Facebook it opens a blank page and it doesn't redirect to the app, if you close the page, go back to the app and click again facebook the user is logged in, but does anyone has any idea how to get rid of the white/blank page?
I have tried 'redirect_uri' and 'display: touch,' but none of this seems to be working anymore.
A blank page after login is a common problem when using Facebook as a sign-in method, especially when we’re in development mode.
It happens because you already logged in and authorized the app, so when it tries to log-in again, it goes blank.
The most straightforward way to fix this is first to check if the user has already logged in and authorized your app before calling the .login() function.
Luckily, Facebook provides a function to do it, where they handle (almost) everything for you.
The getLoginStatus() function
The getLoginStatus() functions determines 1) if a user is signed into Facebook and 2) if the user has already authorized your app.
There are three possible states for a user:
The user is logged into Facebook and has authorized your app, in this case, the function will return: connected.
The user is logged into Facebook but has not authenticated your application, in this case, the function will return: not_authorized.
The user is either not logged into Facebook or explicitly logged out of your application, in this case, we don’t know which one is it, that’s why it returns: unknown.
For example:
When we call getLoginStatus() we’ll get an object similar to this:
{
authResponse: {
userID: '12345678912345',
accessToken: 'kgkh3h4gkh3g4k2h4gk23h4gk2h34gk234gk2h34AndSoOn',
session_Key: true,
expiresIn: '5183738',
sig: '...'
},
status: 'connected'
}
There you can see there’s an authResponse object and a status object. We’ll focus on the status object first, checking for each of the three possible responses.
this.facebookProvider.getLoginStatus(response => {
if (response.status === 'connected') {
// User Authenticated and your App is authorized
} else if (response.status === 'not_authorized') {
// User authenticated but your app isn't authorized yet.
} else {
// the user isn't logged in to Facebook.
}
});
Try this and try to logout first from Facebook before you make call from PWA.
I am using Firebase Authentication with Firebase UI to protect pages by requiring a user to be logged in.
In the documentation I don't see what script we need to use on the top of each page in order to determine if user is logged in. If they are not logged in I want to redirect them to the logon page.
In simple PHP, I can do the following:
require_once("./include/membersite_config.php");
if(!$fgmembersite->CheckLogin())
{
$fgmembersite->RedirectToURL("login.php");
exit;
}
I don't see what is needed to be included in the Firebase JS authentication (and/or using Firebase UI).
In JavaScript you can detect whether the user is signed in with:
var user = firebase.auth().currentUser;
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
See the Firebase documentation on determining what user is signed in.