The getter 'uid' was called on null in flutter - firebase

I'm implementing firebase authentication in flutter application but while trying to get user uid , it is crashing and show noSuchMethodError uid is null , if anyone could help , it is deeply appreciated
That's how i init my variables
class _UserRegistrationState extends State<UserRegistration> {
FirebaseAuth auth;
DocumentReference reference;
Reference storage;
PickedFile imageUri;
final ImagePicker _imagePicker = new ImagePicker();
#override
void initState() {
super.initState();
auth = FirebaseAuth.instance;
// the uid is where the logcat is pointing too and it is null
reference = FirebaseFirestore.instance.collection('users').doc(auth.currentUser.uid);
storage = firebase_storage.FirebaseStorage.instance.ref('avatar').child(auth.currentUser.uid);
}

When you sign in to Firebase Authentication, the SDK automatically persists the user's credentials in local storage. When you restart the app, the SDK tries to restore the user's authentication state from the stored credentials. This requires that it calls the servers to get a new ID token, and for example to check if the account was deleted/disabled in the meantime.
Depending on the platform where you run your code, the calls to the server may have completed before your auth.currentUser runs, or not. To safely respond to the user state, always use an auth state listener as shown in the FlutterFire documentation on responding to auth state changes:
#override
void initState() {
super.initState();
auth = FirebaseAuth.instance;
FirebaseAuth.instance.authStateChanges().listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
reference = FirebaseFirestore.instance.collection('users').doc(auth.currentUser.uid);
storage = firebase_storage.FirebaseStorage.instance.ref('avatar').child(auth.currentUser.uid);
}
});
}

currentUser → User?
Returns the current User if they are currently signed-in, or null if not.
So most likely thing is that you are not logged in and therefore passing null to reference

Related

Cannot get the currentUser's displayName with FirebaseAuth

I have made a sign-in page, and a sign-up page with Firebase Authentication in Flutter and Dart.
After the sign up, I'm trying to retrieve the current user's displayName, however, when I try retrieving it, I seem to get not the current one, but the one that I signed up with before this one.
However, when I for example hot-restart the app, I get the current user's details just fine.
I try to retrieve the current user's displayName property with this code:
static String? getUsername() {
return FirebaseAuth.instance.currentUser?.displayName!;
}
The way I call this, is I initialize a variable to store the username which I get from the method, on a different dart file, different from the signUp page I got. I also call this method in the initState() method.
This is how I sign-up the user and set the displayName:
static void signUpUser(String username, String emailAddress, String password) async {
try {
final credential =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: emailAddress,
password: password,
);
// Here I set the displayName property
await credential.user!.updateDisplayName(username);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {}
else if (e.code == 'email-already-in-use') {}
} catch (e) {}
}
I tried to use the user.reload(), and FirebaseAuth.userChanges() functions, but these did not seem to fix my problem.
Maybe I'm trying to retrieve the displayName property wrong, what am I missing? I'm quite new to developing my own apps and working with Firebase.
The Future that updateDisplayName returns completes when the call has been made to the underlying Firebase SDK. It does not automatically update the user profile in your application at that point though. That will only happen automatically once every hour (when the SDK refreshes the ID token on which that profile is based), or when the user signs out and in again.
To force a refresh of the profile from your application code outside of those automatic conditions, you can call reload() on the user object.

Flutter firebase user problem trying to link to a model

the error I'm getting:
A value of type 'UserA?' can't be returned from the method
'_userFromFirebaseUser' because it has a return type of 'User'
I'm following along this tutorial: Flutter & Firebase App Tutorial #6 - Custom User Model
At about 5:35 into the video he talks about returning the Firebase user object and linking it to the model. Now the video is about 2 years old, so Firebase has moved on a bit. FirebaseUser is now just called User, but I think in my changes I've made a mistake. Here is my code:
class AuthService{
final FirebaseAuth _auth = FirebaseAuth.instance;
//create user object based on firebaseuser
User _userFromFirebaseUser(User? user) {
return user != null ? UserA(uid: user.uid) : null;
}
This is my model:
class UserA {
final String uid;
UserA({ required this.uid });
}
Since FirebaseUser is now just called User I've changed the model to be UserA since I was getting confused.
Any suggestion on what I'm doing wrong?
You're mixing up the two types of users in your code.
The video has two types: FirebaseUser and User, which you have mapped to Users and UserA respectively.
With your types, the function should be:
UserA? _userFromFirebaseUser(User? user) {
return user != null ? UserA(uid: user.uid) : null;
}
Aside from the type change, the ? is needed in Dart nowadays to indicate that you may return either a UserA object or null.

How Can I Get user id in Flutter with Firebase Authentication?

I am currently trying to get the user id in Flutter with Firebase authentication, and I am initializing a variable in initState because I want to use that variable later for a Future call to fetch data from Firebase Real-time database with future builder. (This doesn't work because I have to reload the screen each time and then, get the user id).
And here is my code,
final FirebaseAuth auth = FirebaseAuth.instance;
User user;
String currentUId;
String currentEmail;
#override
void initState() {
super.initState();
user = auth.currentUser;
// Future.delayed(Duration(seconds: 5));
// sleep(Duration(seconds: 5));
currentUId = user.uid;
currentEmail = user.email;
print(currentUId);
}
I tried using sleep, but it didn't work, Is there another place where I can put sleep in, that will make the program wait for the user id then run the rest of the program?
The auth.currentUser variable is initialized automatically by Firebase, once it's verified the user's authenticate state. But since verifying the state may require a call to the server, this may not have completed by the time your currentUId = user.uid runs.
Instead of trying to wait for the result with sleep calls, I recommend using an auth state listener as shown in the documentation on handling authentication state. This gives you a Stream<User>, which you can easily feed into a StreamBuilder.
For a longer example, also see: How to use .currentUser method in flutter

FirebaseAuth Defaultinstance is null / .net core

I have an ionic/angular frontend where I have the user registration via firebase. I already retrieve my firebase token, send it to my .net backend and verify the token with the [Authorize] annotation.
After authorization, I want to decode the token and use the id of the user for further processing.
Step get the token from the "Authorization" header
string authHeader = this.HttpContext.Request.Headers["Authorization"];
var decodedFirebaseToken = await fireBaseAuthenticationHelper.GetUserFromFirebaseIdAsync(authHeader.Substring("Bearer ".Length).Trim());
Step retrieve the decoded token
public async Task<FirebaseToken> GetUserFromFirebaseIdAsync(string token)
{
FirebaseToken decodedToken = await FirebaseAuth.DefaultInstance
.VerifyIdTokenAsync(token);
return decodedToken;
}
The problem now is that the FirebaseAuth.DefaultInstance is always null and throws a null pointer exception. I don't know where or how to initialize the DefaultInstance.
On the FirebaseAuth class is a comment:
public sealed class FirebaseAuth : IFirebaseService
{
//
// Summary:
// Gets the auth instance associated with the default Firebase app. This property
// is null if the default app doesn't yet exist.
public static FirebaseAuth DefaultInstance { get; }
So I am pretty sure I have to initialize it somewhere but I can't find where.
You have to initialize the SDK by creating a new FirebaseApp first. See the code samples in https://firebase.google.com/docs/admin/setup

Android Firebase Authentication - How to Link Existing User Account to Anonymous Account

I am having some trouble understanding how to link an existing email account to an anonymous firebase account. is this possible ? or does it only link if the email account is new ?
when i call the following code to link accounts both the anonymous account and existing account exist. but if its a new email account then i see that the new email account as the same uid as the anonymous account and the anonymous account is gone.
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "linkWithCredential:success");
FirebaseUser user = task.getResult().getUser();
updateUI(user);
} else {
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
// ...
}
});
so my question is: am i able to link anonymous user account to EXISTING user account ? because then my firebase console is going to be filled with anonymous user entries.
UPDATE: Using the firebase mergService here how can i delete the anonymous account ? i dont see it returning a credential for me to delete.
the mergeService describe looks like this:
public class MyManualMergeService extends ManualMergeService {
private Iterable<DataSnapshot> mChatKeys;
#Override
public Task<Void> onLoadData() {
final TaskCompletionSource<Void> loadTask = new TaskCompletionSource<>();
FirebaseDatabase.getInstance()
.getReference()
.child("chatIndices")
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
mChatKeys = snapshot.getChildren();
loadTask.setResult(null);
}
#Override
public void onCancelled(DatabaseError error) {
FirebaseCrash.report(error.toException());
}
});
return loadTask.getTask();
}
#Override
public Task<Void> onTransferData(IdpResponse response) {
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference chatIndices = FirebaseDatabase.getInstance()
.getReference()
.child("chatIndices")
.child(uid);
for (DataSnapshot snapshot : mChatKeys) {
chatIndices.child(snapshot.getKey()).setValue(true);
DatabaseReference chat = FirebaseDatabase.getInstance()
.getReference()
.child("chats")
.child(snapshot.getKey());
chat.child("uid").setValue(uid);
chat.child("name").setValue("User " + uid.substring(0, 6));
}
return null;
}
}
this gets called after user transitions from anonymous user to a real account. how can i then know the credential so i can delete the anonymous account ?
You can't link an existing credential to anonymous user.
You have to basically copy the data of the anonymous user to the existing credential user and then delete the anonymous user.
It is not possible for Firebase to handle this for you. You have 2 users with different uids and data saved on each users, not to mention different profile data on each. Firebase doesn't know which user to keep and how to merge the profile/data. In some cases, data could be saved outside of Firebase services.
FirebaseUI is currently doing a similar mechanism for upgrading anonymous users on sign in. If the credential is new, then linking will succeed without any additional action. If the credential already exists, linking will fail and the developer is expected to handle the merge conflict, copy the data from the non anonymous user and delete the anonymous user after.
This is the web flow in FirebaseUI-web: https://github.com/firebase/firebaseui-web#upgrading-anonymous-users
This is being implemented for FirebaseUI-android:
https://github.com/firebase/FirebaseUI-Android/pull/1185
Here is an example with web, given an authCredential and an anonymous user signed in.
Here is a simple web example how to handle merge conflicts.
let data;
// Default App with anonymous user.
const app = firebase.app();
// Anonymous user.
anonymousUser = app.auth().currentUser;
// Get anonymous user data.
app.database().ref('users/' + app.auth().currentUser.uid)
.once('value')
.then(snapshot => {
// Store anonymous user data.
data = snapshot.val();
// Sign in credential user.
return app.auth().signInWithCredential(authCredential);
})
.then(user => {
// Save the anonymous user's data to the credential user.
return app.database().ref('users/' + user.uid).set(data);
})
.then(() => {
// Delete anonymnous user.
return anonymousUser.delete();
})
})

Resources