I have following code to login in firebase using flutter. This works fine.
FirebaseAuth.instance.signInWithEmailAndPassword(email: myemail, password: mypassword);
After successful authentication, I am creating nw user using below code.
UserCredential userCredentials = await FirebaseAuth.instance.createUserWithEmailAndPassword(email: myemail, password: mypassword);
but, with approach, the current user changes. I want to create the user without changing the current User. Is this possible?
I have found one solution and it's working for me
In main dart file initializeApp like this
void main() async{
await Firebase.initializeApp();
runApp(MyApp());
}
Create a simple/admin user
FirebaseAuth.instance.signInWithEmailAndPassword(email: myemail, password: mypassword);
Add another user
FirebaseApp app = await Firebase.initializeApp(
name: 'secondary', options: Firebase.app().options);
await FirebaseAuth.instanceFor(app: app)
.createUserWithEmailAndPassword(
email: _email, password: _password);
app.delete();
This is a duplicate of Flutter: Firebase Authentication Create User Without Automatically Logging In, but I can't flag the question as it has an open bounty.
You need to create a second instance of FirebaseApp and create the new user with that instance:
static Future<UserCredential> register(String email, String password) async {
FirebaseApp app = await Firebase.initializeApp(
name: 'Secondary', options: Firebase.app().options);
try {
UserCredential userCredential = await FirebaseAuth.instanceFor(app: app)
.createUserWithEmailAndPassword(email: email, password: password);
}
on FirebaseAuthException catch (e) {
// Do something with exception. This try/catch is here to make sure
// that even if the user creation fails, app.delete() runs, if is not,
// next time Firebase.initializeApp() will fail as the previous one was
// not deleted.
}
await app.delete();
return Future.sync(() => userCredential);
}
What you are trying to do is not secure (generating someone else's password)
And you are correct in that sense there is no way to create a password for another email, as an admin.
What you want to do is sendSignInLinkTOEmail.
This is just the same procedure to sign up with GSuit and other popular services as well.
In case if you really need to set up users, you have to use a separate auth module (should be easy to write your own) and not firebase, and then link the users together when they sign up. It's a hacky way and I don't recommend it.
Related
I'm using firebase cloud messaging to send notifications to devices. The problem is that the device token regenrated and added to firestore with different id in every run of the application. I want it to be generated juste once for the first installation of the application.
this is my code :
Future init() async {
_firebaseMessaging.getToken().then((token) {
saveTokens(token);
});
}
Future<void> saveTokens(var token) async {
try {
await _firestore.collection('deviceTokens').add({
'token': token,
});
} catch (e) {
print(e);
}
}
this is how I call it in the main():
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await _msgService.init();
// testFirestore();
FirebaseMessaging.onBackgroundMessage(_messageHandler);
this is _messageHandler function:
Future<void> _messageHandler(RemoteMessage message) async {
print(
'background message ${message.notification!.body} + ${message.notification!.title}');
}
Actually token only refresh on one of that cases:
The app deletes Instance ID
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
So you need to check in your firebase collection if your token (getted on getToken()) is saved yet before add it. If it already exists in your database, don't save it.
For example:
Future<bool> doesTokenAlreadyExist(String token) async {
final QuerySnapshot result = await Firestore.instance
.collection('deviceTokens')
.where('token', isEqualTo: token)
.limit(1)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
return documents.length == 1;
}
The registration token may change when:
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
More :
Update from Play Store - Token remains same.
When close the application and reopen it - Token remains same.
I recommend you should record that token for the user every time your app launches. Then, you don't face any problems.
(add function to init state of home page of your app)
I have a section of an app dedicated to deleting all of a user's data. Firebase auth requires a user to reathenticate before deleting its data, so im trying the following function:
onPressed: () async {
try {
AuthCredential
credential =
EmailAuthProvider
.credential(
email: '',
password: '',
);
_firebaseAuth.currentUser!
.reauthenticateWithCredential(
credential);
BlocProvider.of<
ProfileBloc>(
context)
.add(DeleteProfile(
user: user,
stingrays: stingrayState
.stingrays,
));
Navigator.pushNamed(
context, '/wrapper/');
} on Exception catch (e) {
print(e.toString());
}
},
In this case, setting the email and password as '' should throw an error. My current idea is that the function should run until reauthenciation is called, then an error should be thrown and it does not finish the deleting process. However, it currently does not operate like this, instead running through the entire function. Any idea how to fix this conditional reauthentication method?
Thank you!
You can just call return whenever you want your code to stop and it will.
So after your authentication do this.
_firebaseAuth.currentUser!.reauthenticateWithCredential(credential);
return;
Also reauthenticateWithCredential() is a Future<void> so you have to await it:
return await _firebaseAuth.currentUser!.reauthenticateWithCredential(credential);
I've been struggling with this for months, sinc.e I'm just learning firebase with flutter.
I have a simple button that when pressed should give the option to register or start section with google, but when running I get errors in the console.
There are so many that I don't know which one it is.
Error: Assertion failed:
file:///C:/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.2/lib/src/firebase_core_web.dart:207:11
options != null
"FirebaseOptions cannot be null when creating the default app."
Error: [core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
here in onpress of the button:
child: MaterialButton(
onPressed: () async {
User? user = await Authenticator.IniciarSesion(context: context);
print(user?.displayName);
},
and the class that authenticates
class Authenticator {
static Future<User?> IniciarSesion({required BuildContext context}) async {
FirebaseAuth authenticator = FirebaseAuth.instance;
User? user;
GoogleSignIn objGooglesignIn = GoogleSignIn();
GoogleSignInAccount? objGooglesignInAccount =
await objGooglesignIn.signIn();
if (objGooglesignInAccount != null) {
GoogleSignInAuthentication objGoogleSignInAuthentication =
await objGooglesignInAccount.authentication;
AuthCredential credential = GoogleAuthProvider.credential(
accessToken: objGoogleSignInAuthentication.accessToken,
idToken: objGoogleSignInAuthentication.idToken);
try {
UserCredential userCredential =
await authenticator.signInWithCredential(credential);
user = userCredential.user;
return user;
} on FirebaseAuthException catch (e) {
print("error de auth");
}
}
}
}
Sorry if I put a lot of code. I don't know exactly what the error could be.
There are two issues with your application, first one seems like you are not initializing firebase in the main function properly. Please refer mentioned link for setup.
Flutter firebase setup guide
Additionally as I can see there is no firebase_options.dart in your lib directory which basically manages (api key) configurations for different platforms.
If you have followed steps mentioned in guide correctly you can create these configs using
flutterfire configure
command only after you have already installed flutterfire cli using following command
dart pub global activate flutterfire_cli
I am using google_sign_in for auth in my flutter application.
I followed steps documented here to get started:
https://github.com/flutter/plugins/blob/master/packages/google_sign_in/google_sign_in/example/lib/main.dart
I get idToken as recommended to perform auth on the server side.
This is the code snippet I use to get idToken
_googleSignIn.onCurrentUserChanged.listen(
(GoogleSignInAccount account) {
setState(() {
developer.log("************Changing account");
_currentUser = account;
account.authentication.then((key){
developer.log("########### Changing token");
_userToken=key.idToken;
});
});
});
When I send idToken (_userToken in above example) it works fine for sometime, and later I see the following error message on the server side:
Token expired, 1593370077 < 1593384191
IT looks like token has an expiration time and expires after a while.
I tried moving above code snippet from initState() to build(). Here my assumption if I call it everytime when I am building the widget I should get a new token. THAT DIDN'T WORK
Reason I thought it might work was because when I "Run .dart" (not hot reload) it works. This made me assume moving it to build might work . It didn't work
My question: What is the programmatic way to refresh token, or get a new token in flutter using google_sign_in.
Thanks for your help!!
The idToken expires every 30 minutes.
To refresh the token you can either user the API or do a silent login like this:
Future<String> refreshToken() async {
final GoogleSignInAccount googleSignInAccount =
await googleSignIn.signInSilently();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
await auth.signInWithCredential(credential);
return googleSignInAuthentication.accessToken; //new token
}
I am using multiple Firebase sign in methods in my app (Facebook, Google, Phone, etc). But once the user is logged in, I am unable to determine which provider was used to sign in.
I tried below(very close to the recommended solution. But does not work):
_auth.currentUser().providerData[0].providerId
I expect it to return something like "google.com" or "facebook.com"
Instead it returns "firebase"
I cant find any other solution where it clearly lets us determine if a google or facebook sign in was used. All solutions in the forum iOS specific or for web. Can't find anything flutter specific. Appreciate any help in advance.
I checked and _auth.currentUser().providerData[0].providerId does provide "google.com" or "facebook.com"
Not sure at what point it showed me "firebase". Will post to this if I figure this out
You can use the following code :
#override
Future<void> signOut() async {
final FirebaseAuth _auth = FirebaseAuth.instance;
try {
final _providerData = _auth.currentUser!.providerData;
if (_providerData.isNotEmpty) {
if (_providerData[0]
.providerId
.toLowerCase()
.contains('google')) {
await GoogleSignIn().signOut(); // google signOut
} else if (_providerData[0]
.providerId
.toLowerCase()
.contains('facebook')) {
await FacebookAuth.instance.login(); // facebook signOut
}
}
await _auth.signOut(); // firebase signOut
} catch (e) {
print(e);
}
}
I am not sure about facebook since I have never implemented login with facebook, but for Google, you may be able to do something like this.
You probably have a statement similar to GoogleSignInAccount googleUser = await _googleSignIn.signIn(). Why not check if google User is null or not once the user is signed in or on auth change? This will let you know if the user signed in with google.
Similar functionality for facebook should be possible but I just don't know if it is the same.
If googleUser != null then google was used.
If say facebookUser != null then facebook was used,
Then if googleUser is null and say facebookUser is null it was email.
Maybe this is helpful, maybe not, but it is just what I could think of right now.