Flutter Firebase authentication: reverting back to a specific anonymous user - firebase

The Firebase authentication documentation for Kotlin states that:
The call to linkWithCredential will fail if the credentials are already linked to another user account. In this situation, you must handle merging the accounts and associated data as appropriate for your app:
And then a code example is provided, the Flutter equivalent of which could be written as follows:
final prevUser = FirebaseAuth.instance.currentUser;
try {
final result = await FirebaseAuth.instance.signInWithCredential(credential);
final currentUser = result.user;
// Merge prevUser and currentUser accounts and data
// ...
} catch (e) {
// ...
}
Let's assume prevUser is an anonymous user. If the merge of prevUser and currentUser accounts and data doesn't succeed, is there any way to restore the Firebase sign-in state to what it was prior to the call to signInWithCredential, i.e. to make prevUser the currently signed in Firebase user again?
My app backend has its own representation of a user - AppUser - that is keyed by Firebase user uid, and there is an AppUser user that corresponds to (i.e. has the same uid as) prevUser. I don't want to recover from the failed merge by signing in anonymously, because that would give me a new anonymous user, with a different uid, which doesn't match up with said AppUser user.

No. Once an anonymous user signs out, or becomes replaced with a new sign-in, that anonymous account is effectively lost forever, from the perspective of the client app. The client app was the only holder of credentials that could perform a sign-in on that account.
You might want to consider at least persisting the uid of that account, then provide it to whatever process performs the merge. This would typically be done on a backend so that it could bypass any security restrictions on what can be done with an account when the user is not controlling it directly from a client app.

Related

is UID in firebase automatically created/read for each user?

I'm sorry if my question is basic question...
is UID in firebase automatically created when we implement .setUid() at the first user sign-up account? and if we are login to that user account and implement .getUid(), can we retrieve the same UID?
I use Android Studio and Kotlin as programming language
No matter how you implement authentication on your app, firebase will automatically set a uid for each account created. If you go to the auth section of your firebase console and manually add an account, you will see on the right hand side a uid generated for that account.
To reference this uid within your code the uid does not need to be stored in any database solution for the uid is attatched to the account within FirebaseAuth..
To pull the uid for reference once the user has signed in, first you need to set the auth global variable..
private lateinit var auth: FirebaseAuth
Then anywhere within the scope of your functions you can set your uid reference variable like this..
val myUid = FirebaseAuth.getInstance().currentUser.uid;

How to verify custom auth claim upon login?

Similar to Uber, I have two applications, one for clients and one for drivers. Is it possible to know which role type the user has upon login? For instance, if I have a client account and I try to log in on the driver's application I should get the error: "client accounts cannot be used to log into the driver application".
Let's say I stored the user's account type (driver or client) in a custom auth claim, would it be possible to access that while firebase auth is verifying the email and password, or does the user have to log in successfully before I can verify the value of the custom auth claim?
Essentially, if the user tries logging into the wrong application, I want it to come back as an error without actually logging them in. So far I've only been able to check for this after the user logs in using getIDTokenResult.
Any help is appreciated! :)
Essentially, if the user tries logging into the wrong application, I want it to come back as an error without actually logging them in.
You seem to be mixing authentication (the user enters credentials that prove who they are) with authorization (the user is allowed to do certain things based on who the are). Firebase Authentication solely is concerned with the former: allowing the user to sign in once they enter the correct credentials for their account. Once the user is signed in, your application code can then determine whether they're allowed to perform certain actions.
For your specific use-case for example, the idiomatic approach is to:
Sign the user in to Firebase Authentication.
Check whether their token contains the necessary claim for the app they're trying to use.
If so, allow them to continue to the main screen of your app.
If not, inform them of that fact and don't allow them to continue.
As you can see here, it is your application logic that handles all authorization logic, while Firebase takes care of the authentication.
The user must be logged in before checking the claims and anyways you cannot prevent anyone from logging in if it's a same firebase project. You should check the claim after login and if the user has logged into wrong application, just force them to logout. Security Rules can be used to prevent unauthorized access.
firebase.auth().signInWithEmailAndPassword().then(async ({user}) => {
const claims = await user.getIdTokenResult()
// check for claim
// if not valid then logout or redirect to relevant pages
await firebase.auth(can ).signOut()
})
You can show your error alerts after signing out.
If you really want to check the claim before logging the user in then you would have to use cloud functions which checks claims for the entered email but this method may not be useful in other sign in providers such as Google or Facebook.
Although I won't recommend using Cloud functions just to check the claims before users logs in as it just can be bypassed on the frontend and as mentioned above, forcing the user to logout should be enough. But here's a cloud function you can use to check the claims.
exports.checkClaim = functions.https.onCall((data, context) => {
const {email} = data;
return admin
.auth()
.getUser(uid)
.then((userRecord) => {
const {customClaims: {driver, client}} = userRecord;
if (driver) return {role: "driver"}
if (client) return {role: "client"}
return {error: "No role found"}
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
});
Then call the function before you run the signInWithEmailAndPassword method.
const checkUserRole = firebase.functions().httpsCallable('checkClaim');
checkUserRole({ email: "user#domain.tld" })
.then((result) => {
const {role, error} = result;
if (error) {
alert("Something went wrong. No roles found")
} else {
console.log(`Your role is: ${role}`)
}
});
Again as mentioned above this sounds a bit overkill but if it's necessary or you prefer to do it that way then you use this function.

Is there any way to get firebase Auth UID without login?

What i want to know is without login get Auth User UID from firebase
that already registered user
I already read firebase document but all the explain focus on when user logged only at that time can get UID...
but i just want to get UID and user email address without login situation
Is there any way?
Nope, there is no way using firebase authentication to retrieve the uid or email is the user is currently not logged in.
The only other way to actually retrieve them, is to use firebase database. So, when the user registers in your application, you also send the data of the user to the database and then you will be able to retrieve the data later on even if he is not logged in.
For example (on register) you can send this data to the database:
users
userId
email : email_here
name : name_here
Your question is not clear.
You can create the user via the Admin SDK if you know the user's credentials. You can also lookup an existing user's information by email or uid with the Admin SDK.
Learn more about this from the official docs.
You can apply a trick to do this. Though this is not an optimal solution.
One thing you have to remember that, "There is no way to get a UID without login".
Create a dummy user from your backend with a dummy email and password.
Send the email and password from the backend to your client-side app. You can always hash the password if you want to give an extra security layer.
Now call signInWithEmailAndPassword function from firebase SDK and provide email and password which came from the backend.
The user is already registered in the backend, so now you can get the UID from your client app.
mAuth.signInAnonymously()
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInAnonymously:success");
FirebaseUser user = mAuth.getCurrentUser();
Log.d("userstatus","user id is "+user.getUid());
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInAnonymously:failure", task.getException());
}
// ...
}
});

How to use the same firebase anonymous user in a flutter app

I'm currently developing a Flutter app for in a internal project whose process is :
You can log in as an authenticated user (mail / passwd) and complete some actions / tasks / validate things
You can log anonymously and complete some actions, BUT you need to validate these actions through an authenticated user (AU).
By doing so, each time an AU log himself, he can validate and then switch back to anonymous mode. The problem is that Firebase creates a new anonymous user each time.
The app could be utilized on multiple devices across the company, which could create 100's of anonymous users a day, while in fact it was only 6-7 users, so what can I do to avoid this ?
I've read about customIdToken but I haven't come to a solution for my problem.
Here is the code I'm using:
Future<FirebaseUser> signInAnonToken(String token) async {
FirebaseUser user = await _firebaseAuth.signInWithCustomToken(token: token);
return user;
}
FirebaseUser userAnon = await widget.auth.signInAnonToken("useranonuid");
Where "useranonuid" is the uid of the anonymous user but also the token I get by using the getIdToken(refresh:true) method
Thanks in advance.
The problem is that Firebase creates a new anonymous user each time.
The workaround that I did on my end is to add deleting the anonymous user on the end of each workflow. This should prevent the Firebase project hitting the 100 million anonymous user account limit.
There's no way to restore previous Firebase Anonymous Auth instance. That would defeat the purpose of being "anonymous" in the first place.

Firebase Auth: link two pre-existing accounts

I have read this:
"Account linking can only be performed at the point at which a new
account is created. It is not possible, in other words, to link two
pre-existing accounts."
Is it still true?
I'd like this workflow :
User logs in the app and take his Anonymous uid;
Then User does the login (user previously registered) and obviously has his uid;
Now when the user does the logOut I'd like to give him his previous Anonymous uid, not a new one.
Is this possible?
It's not possible if you want to link your anonymous user to an existing account. It will give you an error: 'auth/credential-already-in-use'. You have to manually merge your two accounts.
It is possible to convert an anonymous account to a permanent account. You can do that by logging in the user into the new account, getting it's credential and then use it to link with the anonymous account, as mentioned on the documentation:
auth.currentUser.link(credential).then(function(user) {
console.log("Anonymous account successfully upgraded", user);
}, function(error) {
console.log("Error upgrading anonymous account", error);
});
But when the user logs out, he can't get that previous uid back. Because anonymous accounts are temporary, as mentioned on the documentation:
You can use Firebase Authentication to create and use temporary
anonymous accounts to authenticate with Firebase
And I think it makes sense. Because if a user was anonymous, it means he has no identification. So there's no way you can tell who was using that uid before.

Resources