I'm trying to implement different login options for my flutter app users, but can't make the facebook one work(google and email are ok).
I've followed the installation guide from the package flutter_facebook_auth but still getting an error when the token provided from facebook is going to be used as a credential to create the firebase user:
my code:
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:firebase_auth/firebase_auth.dart';
final FirebaseAuth _auth = FirebaseAuth.instance;
String usermail = "";
Future returnToken(User user) async {
token = word + await user.getIdToken();
}
Future<List<String>> facebookSignin() async {
try {
final _instance = FacebookAuth.instance;
final result = await _instance.login(permissions: ["email"]);
if (result.status == LoginStatus.success) {
final OAuthCredential credential = FacebookAuthProvider.credential(result.accessToken.token);
final a = await _auth.signInWithCredential(credential); //the error is in this line
await _instance.getUserData().then((userData) async {
await _auth.currentUser.updateEmail(userData["email"]);
userMail = userData["email"];
});
await returnToken(a.user);
return ["ok"];
} else if (result.status == LoginStatus.cancelled) {
return ["Erro!", "Login cancelado"];
} else
return ["Erro!", "Falha no login"];
} catch (e) {
return ["Erro!", e.toString()];
}
}
The problem was on the secret key option:
I didn't add it on my app, so having this setting turned on blocked the app from generating a valid token to firebase.
Related
I'm completely new to flutter development and I am making a login for admins in my flutter mobile app.
The email address used in the login already exists in Firebase Authentication, but before I have it proceed to logging in the app, I first need to check if the inputted email address is stored in Realtime Database. How do I go about this in terms of code?
The flow is like this: user inputted "abc#gmail.com" as email address for login. App checks rtdb if there is a value of "abc#gmail.com", if true, proceed with login.
I understand I have to use
var rtdbref =
FirebaseDatabase.instance.reference().child("Admins").child("adminEmail");
but after that I have no idea how to have Flutter read the values. Any help is very much appreciated! Thank you :)
Image for rtdb reference:
screenshot of rtdb
Code I have so far:
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
var rtdbref =
FirebaseDatabase.instance.reference().child("Admins").child("adminEmail");
void loginAdmin(BuildContext context) async {
try {
final User? firebaseUser =
(await _firebaseAuth.signInWithEmailAndPassword(
email: emailTextEditingController.text,
password: passwordTextEditingController.text))
.user;
if (firebaseUser != null) {
var isAdmin = await rtdbref.child("Admins").once();
if (isAdmin.value["adminEmail"] == emailTextEditingController.text) {
//check if admin here
if (firebaseUser.emailVerified) {
//if (firebaseUser.emailVerified) {
usersRef.child(firebaseUser.uid).once().then((DataSnapshot snap) {
if (snap.value != null) {
Navigator.pushNamedAndRemoveUntil(
context, Navbar.idScreen, (route) => false);
//displayToastMessage("Homepage", context);
}
});
} else {
displayToastMessage("Please verify your account", context);
await firebaseUser.sendEmailVerification();
}
} else {
_firebaseAuth.signOut();
displayToastMessage("Account does not exist", context);
}
}
} on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
displayToastMessage("Wrong password", context);
}
if (e.code == 'too-many-requests') {
displayToastMessage("Please try again after 2 minutes", context);
}
if (e.code == 'user-not-found') {
displayToastMessage("User not found", context);
}
}
//displayToastMessage("Admin login test", context);
}
Update: I've attempted the following but still cannot seem to get it to read the adminEmail values of node Admins. What am I missing here? I feel like im so close
DatabaseReference adminsRef =
FirebaseDatabase.instance.reference().child("Admins");
var isAdmin = adminsRef
.orderByChild("adminEmail")
.equalTo(emailTextEditingController.text);
This question already has answers here:
In Dart/Flutter, how can I find out if there is no Collection in the Firestore database?
(4 answers)
Closed 1 year ago.
im very new to dart/firebase and im currently experimenting with it. Im trying to figure out if theres a way to find out if a collection exists or not.
Ive created a method where everytime a user registers, it creates a collection named after their userid. And everytime they sign in "I want to check if it exists", if not create it.
I dont want a user who signs in the 'dashboard' page without having a collection.
My current coding, creates a collection when they register, and also when the sign in lol, cant figure out to check if collection exists.
auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'database.dart';
class Authentication {
static Future<User?> signInUsingEmailPassword({
required String email,
required String password,
required BuildContext context,
}) async {
FirebaseAuth auth = FirebaseAuth.instance;
User? user;
try {
UserCredential userCredential = await auth.signInWithEmailAndPassword(
email: email,
password: password,
);
user = userCredential.user;
// Create User Database file
await Database.createUserDataFile(
uid: user!.uid,
surname: 'surname',
mobile: 12345,
);
// Creates User Database
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided.');
}
}
return user;
}
static Future<User?> registerUsingEmailPassword({
required String name,
required String email,
required String password,
required BuildContext context,
}) async {
FirebaseAuth auth = FirebaseAuth.instance;
User? user;
try {
UserCredential userCredential = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
user = userCredential.user;
// Create User Database file
await Database.createUserDataFile(
uid: user!.uid,
surname: 'surname',
mobile: 12345,
);
// Creates User Database
await user.updateDisplayName(name);
await user.reload();
user = auth.currentUser;
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
return user;
}
static Future<User?> refreshUser(User user) async {
FirebaseAuth auth = FirebaseAuth.instance;
await user.reload();
User? refreshedUser = auth.currentUser;
return refreshedUser;
}
}
database.dart
import 'package:cloud_firestore/cloud_firestore.dart';
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
// Database Collection Name
final CollectionReference _mainCollection = _firestore.collection('_TestFB');
class Database {
static String? userUid;
// Create User Data File
static Future<void> createUserDataFile({
required String uid,
required String surname,
required int mobile,
}) async {
// - Col:_TestFB/Doc:UserData/Col:profile/
DocumentReference documentReferencer =
_mainCollection.doc('UserData').collection(uid).doc('Profile');
Map<String, dynamic> data = <String, dynamic>{
"surname": surname,
"mobile": mobile,
};
// Check if user Exists
//print('users exists?');
//
await documentReferencer
.set(data)
.whenComplete(() => print("UserData Profile Created for -- " + uid))
.catchError((e) => print(e));
}
}
If a collection doesn't exist, that technically means there are no documents in it. You can query for that collection and if it has 0 documents in it then that could mean it's absent.
FirebaseFirestore.instance
.collection('colName')
.limit(1)
.get()
.then((checkSnapshot) {
if (checkSnapshot.size == 0) {
print("Collection Absent");
}
});
The .limit(1)will fetch only one document from that collection if exists so that's important or you'll end up reading all the documents from it.
[createUserEmailAndPasswordError]
Error Screenshot:
I am trying to Auth login using firebase and this error comes up. I tried suing this. or type String before it as it was given in quick fix option but didn't work.
Full error message - The named parameter 'email' isn't defined.
Try correcting the name to an existing named parameter's name, or defining a named parameter with the name 'email'. dart(undefined_named_parameter)
Full code -
import 'package:firebase_auth/firebase_auth.dart';
import 'package:socialMediaApp/models/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
//create user obj based on FirebaseUser
Users _userFromFirebaseUser(User user) {
return user != null ? Users(uid: user.uid) : null;
}
// sign in with email & password
// register with email & password
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential userCredential = (await _auth
.createUserWithEmailAndPassword(email: email, password: password));
User user = userCredential.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
I am working on a project in which user data will be saved in Fire store in this i am making new document for user when the user sign In with google. here is my code below
import 'package:firebase_auth/firebase_auth.dart';
import 'package:gfd_official/User/User.dart';
import 'package:gfd_official/services/database.dart';
import 'package:google_sign_in/google_sign_in.dart';
class GSignInhelp {
final FirebaseAuth _auth = FirebaseAuth.instance;
//Firebase User
Userdat _userFromFirebase(User user) {
return user != null ? Userdat(uid: user.uid) : null;
}
//auth change user stream
Stream<Userdat> get user {
return _auth.authStateChanges().map(_userFromFirebase);
}
Future signInWithGoogle() async {
GoogleSignIn googleSignIn = GoogleSignIn();
final account = await googleSignIn.signIn();
final auth = await account.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: auth.accessToken,
idToken: auth.idToken,
);
try {
final res = await _auth.signInWithCredential(credential);
User user = res.user;
await DatabaseService(uid: user.uid)
.updateUserRole(user.displayName, user.email, 'basic');
return _userFromFirebase(user);
} catch (e) {
print(e.toString());
return null;
}
}
Future logOut() async {
try {
GoogleSignIn().signOut();
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
I am successfully able to change user role in fire store but as you can see when user signs in the database values will be set to default but I don't want this. So, my question is how can I check that if user is signed in for first time or returning user.
If user is returning then I don't want to reset user data in Fire store and If user is new then create document in Fire store with default values.
Conclusion, How can I check that When user signs in with google that is user a existing user or new a user?
You can check the user whether he is a new or previously registered user via User Credential and through you can retrieve the authResult.additionalUserInfo.isNewUser if the user is not already registered before.
You can use this code:
Future<UserCredential> signInWithGoogle(BuildContext context) async {
FirebaseAuth _auth = FirebaseAuth.instance;
// Trigger the authentication flow
final GoogleSignInAccount googleUser = await GoogleSignIn().signIn();
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
// Create a new credential
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final UserCredential authResult =
await _auth.signInWithCredential(credential);
final User user = authResult.user;
///Her to check isNewUser OR Not
if (authResult.additionalUserInfo.isNewUser) {
if (user != null) {
//You can her set data user in Fire store
//Ex: Go to RegisterPage()
}
}
} else {
//Ex: Go to HomePage()
}
return await FirebaseAuth.instance.signInWithCredential(credential);
}
Here is the full code for Google sign in and sign out :-
class GSignInhelp {
final FirebaseAuth _auth = FirebaseAuth.instance; //Firebase User
Userdat _userFromFirebaseUser(User user) {
return user != null ? Userdat(uid: user.uid) : null; } //auth
change user stream
Stream get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
Future signInWithGoogle() async {
GoogleSignIn googleSignIn =
GoogleSignIn();
I have implemented phone number authentication in a flutter app using firebase phone auth. It is working fine in Android. But it is not working properly in iOS as many users are facing error after they submit sms verification code, though a lot others are using the app just fine. What can be the possible reasons for this scenario? I have submitted my code below.
Number Submission
void _verifyPhoneNumber() async {
final PhoneVerificationCompleted verificationCompleted =
(AuthCredential phoneAuthCredential) async {
final FirebaseUser user =
await _auth.signInWithCredential(phoneAuthCredential);
if (user != null) {
phone = user.phoneNumber;
fid = user.uid;
saveLogin(context);
} else {
_showErrorDialog("User Verification Error!");
}
};
final PhoneVerificationFailed verificationFailed =
(AuthException authException) {
_showErrorDialog("Phone Verification Failed");
};
final PhoneCodeSent codeSent =
(String verificationId, [int forceResendingToken]) async {
_verificationId = verificationId;
setState(() {
_title = "Verify SMS Code";
phoneInput = false;
phoneSubmit = false;
codeInput = true;
codeSubmit = true;
});
};
final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
(String verificationId) async {
_verificationId = verificationId;
setState(() {
_title = "Verify SMS Code";
phoneInput = false;
phoneSubmit = false;
codeInput = true;
codeSubmit = true;
});
};
await _auth.verifyPhoneNumber(
phoneNumber: "+880" + _mobileNumber,
timeout: const Duration(seconds: 5),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
}
Code Submission
void _signInWithPhoneNumber(String _code) async {
final AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: _verificationId,
smsCode: _code,
);
final FirebaseUser user = await _auth.signInWithCredential(credential);
if (user != null) {
phone = user.phoneNumber;
fid = user.uid;
saveLogin(context);
} else {
_showErrorDialog("User Verification Error!");
}
}
Plugins Used
google_sign_in: ^4.0.1+3
firebase_auth: ^0.11.0
Try adding the REVERSE_CLIENT_ID custom URL schemes to your Xcode project.
According to the firebase documentation:
iOS setup note: App verification may use APNs, if using a simulator (where APNs does not work) or APNs is not setup on the device you are using you must set the URL Schemes to the REVERSE_CLIENT_ID from the GoogleServices-Info.plist file.
How to add custom URL schemes to your Xcode project:
Open your project configuration: double-click the project name in the left tree view. Select your app from the TARGETS section, then select the Info tab, and expand the URL Types section.
Click the + button, and add a URL scheme for your reversed client ID. To find this value, open the GoogleService-Info.plist configuration file, and look for the REVERSED_CLIENT_ID key. Copy the value of that key, and paste it into the URL Schemes box on the configuration page. Leave the other fields blank.
References from here:
https://pub.dev/packages/firebase_auth
https://firebase.google.com/docs/auth/ios/phone-auth