How to prevent Firebase anonymous user token from expiring - javascript

I'm using anonymous authentication is a Firebase app. I just noticed that I have over 100 anonymous users now registered even though all I've been doing is testing the app. It looks like the expiration time for the user token is quite short, and as soon as it expires the next login causes a new user to be created.
What is the best way to avoid this? I could presumably refresh the user's token but I'm not sure how to this since in onAuthStateChange the user parameter is null if the user has expired.
Or should I changed the expiration time? If so, how do I do this? I found some instructions for doing so in the old Firebase docs but can't see how to do it in the latest version.
UPDATE: Currently I am initializing the app and authenticating the (anonymous) user like so:
firebase.initializeApp(FIREBASE_CONFIG);
firebase.auth().onAuthStateChanged(user => {
if (!user) {
firebase.auth().signInAnonymously().catch(error => {
console.error('Failed to authenticate with Firebase', error);
});
}
});

Related

why firebase authentication is slow?

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.

Msal v2 library, handle logout for SSO (Node.js and Vue.js)

The problem:
Using msal v2, when user log in to the app via Microsoft account, it saves params to the sessionStorage and it all works great, problem happens when user logs out in the Office.com or any other site using Microsoft SSO. Since the data is still saved in sessionStorage (tried same with localStorage) the AcquireSilentToken(...) resolves with the cached data, even though the user has been logged out.
Tried How to know if a given user is already logged in with MSAL?
It suggest using AcquireSilentToken(...) but it resolves promise without error since it checks sessionStorage.
My case:
In the middleware I would like to do:
const promise = msalInstance.acquireTokenSilent(graphScopes);
promise.then(resp=>{
//User is logged continue next();
}).catch(error=>{
//User is not logged in clear sessionStorage/localStorage and next('/login')
});
So if anyone can help me with the way of asking the thru msal if user has logged out. I would really appreciate it.
This behavior is by design. AAD services uses cookies to remember who you are and to automatically sign you in.
The sign-out process for services forces the session cookies to expire. These session cookies are used to maintain your sign-in state when you use these services. However, because the web browser is still running and may not be updated to handle cookies correctly, you may have a cookie that is not updated to expire and finish the sign-out process. By default, these cookies are valid for eight hours or are set to expire when you close all web browsers.
const promise = msalInstance.acquireTokenSilent(graphScopes);
promise.then(resp=>{
const logoutRequest = {
account: instance.getAccountByHomeId(homeAccountId),
postLogoutRedirectUri: "your_app_logout_redirect_uri"
}
instance.logoutRedirect(logoutRequest);
}).catch(error=>{
//User is not logged in clear sessionStorage/localStorage and next('/login')
});
Also this is a known issue.

how to reauthenticate user with firebase authentication?

I'm new to firebase.
In my nuxt js project with multiple pages, firestore rule is set to read or write once request.auth != null.
so if when refresh in a page, auth will be gone and it display error 'permission-denied' in terminal.
i tried Authentication State Persistence LOCAL but it doesn't work.
What is the purpose of using these auth persistence mode ?
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(function() {
return firebase.auth().signInWithEmailAndPassword(email, password);
})
Auth session is automatically persistent on the frontend of your app, however Nuxt.js contains frontend and backend part. If you are storing user data somewhere on the frontend, you probably need to wait until the user data become accessible.
Example of the listener:
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log('User is logged: ', user);
}
});
However this will make user accessible only on the frontend, if you want to preload data on the backend you would need to store id and refresh token in the cookies or use Nuxt Firebase module which should handle service worker for you.
So, in your case it looks like you are trying to read the data before your user data become accessible (this can be caused by trying to fetch data on the backend).

How do I persist user authentication using the Firebase refresh token?

I am building a React Native app which uses Firebase phone authentication for user login. Authentication works fine but the token expires after an hour. I have read that I need to use the refresh token to refresh the idToken, but nowhere on the Firebase docs does it explain how to do this. It only explains how to revoke refresh tokens, and I can't even find it.
I am using the react-native-firebase package.
My questions are: how to I get the refresh token, how do I use it, and do I really need to call Firebase every hour to update my idToken?
I am currently getting my idToken like this:
const authenticate = async (credential) => {
try {
const { user } = await firebase.auth().signInWithCredential(credential);
const accessToken = await user.getIdToken();
return accessToken;
} catch (error) {
console.log(error);
}
}
I then take the token and store it locally using AsyncStorage and check if the token exists every time the app is launched.
Thanks in advance.
From https://rnfirebase.io/reference/auth/user#getIdToken
It seems that using user.getIdToken() refresh the token if it has expired.
You can always use the forceRefresh option if you want to refresh the token even if it's still valid.

Sometimes firebase.auth().onAuthStateChanged returns user of null when I refresh the page

Precondition
$npm install --save firebase#4.11.0
issue
I'm using firebase authentication on my web application.
In my app, I implemented onAuthStateChanged for client side js like below.
firebase.auth().onAuthStateChanged((user) => {
if(user) {
//logged in
} else {
//do sth
}
});
After login, I confirmed this method will return actual user obj, but if I refresh the page, then user might be null.
Curiously, sometimes user won't be null.
I'm afraid there are some limitation of calling onAuthStateChanged, but currently I have no idea.
How should I deal with this issue?
update
Let me share my minimal example.
My app is working with express.js.
There are two URLs like below.
/login
/main
In the login page, I implemented authentication method.
If the login is successfully finished, then user will be redirected to '/main'.
//login.js
import firebase from 'firebase';
var config = {...};
firebase.initializeApp(config);
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider)
.then((result) => {
return result.user.getIdToken(true);
}).then((idToken) => {
if(idToken) {
location.href = '/main';
}
});
In the main page, there is no login method.
main.js is only checking whether user is logged in.
//main.js
import firebase from 'firebase';
var config = {...};
firebase.initializeApp(config);
firebase.auth().onAuthStateChanged((user) => {
if (user) {
//initialize main page.
} else {
location.href = '/login';
}
}
I think login status is stored on LocalStorage of web browser.
This means that, after finishing loading of main.js, onAuthStateChanged will be automatically fired with user information, but not working as I expected.
I'm sure that persistence of login information is correct because official document says the default setting is LOCAL for web client.
https://firebase.google.com/docs/auth/web/auth-state-persistence
my question
Should I implement onAuthStateChanged with another way?
How can I ensure user is logged in after reload?
e.g.
import $ from 'jquery';
$(document).on('ready', () => {
onAuthStateChanged((user) => {...});
});
Or could you show me the correct way?
Workaround
I decided to remove session and set redirection to login page if null is returned. This is not a solution, but a workaround currently...
You're not calling onAuthStateChanged. Instead you're telling Firebase to call you when the authentication state changes, which may happen a few times when the page is being re-loaded
When a page is getting loaded and there was previously a user signed in, the auth state may change a few times, while the client is figuring out if the user's authentication state it still valid. For that reason, you may see a call with no user before seeing the final call with the actual signed in user.
The fact it's sometimes null and sometimes not null likely points to an async problem. Are you making the check in the if statement above? All references to the user should be within the callback. If that all checks out, maybe check that authentication is being properly initiated.
onAuthStateChanged is an observer as stated in firebase docs, which gets triggered when the auth state is changed like user signed in, signed out, pwd change. To check if user is logged in or not you should use firebase.auth().currentUser which will give you the current logged in user. As you said your state is local firebase.auth().currentUser will always give you user unless user is signed out.

Categories

Resources