Flutter Firebase web authentication setup issue - flutter

Description:
Trying to setup firebase authentication for web. Please guide how to implement and the steps needed for it. Or if there is some tutorial that explain it well. Need to way to implement authencication for web version only. Any help would be appreciated alot.
Here is I tried but not working for auth and getx. Thank you.
Future<void> checkLoginAndRediect() async {
Authentication authentication = Authentication();
final UserController userController = Get.find(tag: 'userController');
await authentication.autoLogin();
if (userController.previouslyLoggedIn) {
Get.offAll(
const Home(),
);
} else {
Get.offAll(
const SignupPage(),
);
}
Future<bool> init() async {
if (userID.isNotEmpty) {
userController.userID = userID;
var document = await FirebaseFirestore.instance
.collection('users')
.doc(userID)
.get();
if (document.exists) {
//updaiting user data locally from firebase
userController.setUser(
userID,
document.data()!['name'],
document.data()!['phone'],
document.data()!['email'],
document.data()!['username'],
document.data()!['profilePictureLink'] ??
"https://firebasestorage.googleapis.com/v0/b/matab-a53a8.appspot.com/o/DefaultProfile.png?alt=media&token=716eca5e-b939-4dfa-8e8e-72b0efc75f7f", //there is always a default profile picture but for those user which are reqistered earlier it will replace their as soon as they sign in, with default dummy pic
);
//fetching user's addresss from firebase
addressDatabaseService
.getAddress(userID)
.then((value) {})
.catchError((error) {
return false;
});
//fetching bank details here
var bankDetails =
FirebaseFirestore.instance.collection('bankDetails').doc("1").get();
bankDetails.then((value) {
transactionController.setBankDetails(
value.data()!['bankName'],
value.data()!['accountNumber'],
value.data()!['accountTitle'],
value.data()!['bankBranch']);
orderController.userID = userID;
}).catchError((error) {
debugPrint(error.toString());
});
//fetching user optional details from firebase if already exists there
optionalProfileDetailsController.getProfileDetails(
userID); //this will fetch and store user optional details in controller, controller calls database service itself to fetch data from database
userController.previouslyLoggedIn =
true; //updating user already exists flag to true
}
return true;
} else {
return false;
}
}
Future<void> autoLogin() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool userStatus = prefs.containsKey('uid');
if (userStatus) {
String? uid = prefs.getString('uid');
userID = uid!;
userController.userID = userID;
await init();
userController.previouslyLoggedIn = true;
} else {
userController.previouslyLoggedIn =
false; //if this is false then in main.dart=>checkLoginAndRediect we will check for this and redirect user to signup page
debugPrint("not connected");
}
}
login(String identifier, String password) async {
String errorMessage;
final auth = FirebaseAuth.instance;
try {
final UserCredential userCredential = await auth
.signInWithEmailAndPassword(email: identifier, password: password);
final User? user = userCredential.user;
if (user != null) {
if (!user.emailVerified) {
Get.snackbar(" Email not Verified ", "Please verify your email.",
colorText: whiteColor,
backgroundColor: Colors.red,
duration: const Duration(seconds: 5),
snackPosition: SnackPosition.BOTTOM);
return;
} else {
userID = user.uid;
userController.userID = userID;
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('uid', userCredential.user!.uid);
await init();
Get.offAll(() => const Home());
}
}
} on FirebaseAuthException catch (error) {
switch (error.code) {
case "user-not-found":
errorMessage = "Incorrect Email or Password".tr;
break;
case "wrong-password":
errorMessage = "Incorrect Password".tr;
break;
case "invalid-email":
errorMessage = "Email is not valid.".tr;
break;
default:
errorMessage = "Something Went Wrong,";
}
Get.snackbar(errorMessage, "Please Try Again".tr,
snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red);
}
}
signUp(String name, String phone, int usercnic, String email, String password,
String confirmPassword) async {
//below is a default image link, it will be replaced by user's profile picture when he/she sign up for the first time later on he can updateq his/her profile picture
String profilePictureLink =
"https://firebasestorage.googleapis.com/v0/b/matab-a53a8.appspot.com/o/DefaultProfile.png?alt=media&token=716eca5e-b939-4dfa-8e8e-72b0efc75f7f";
final auth = FirebaseAuth.instance;
String errorMessage;
if (confirmPassword != password) {
generateError("Incorrect Confirm password".tr, "Please try again".tr);
return;
}
try {
final UserCredential signUPResponse =
await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
User? user = signUPResponse.user;
if (user != null) {
userDBService.addUser(
user.uid, name, phone, email, usercnic, profilePictureLink);
userController.setUser(
user.uid, name, phone, email, usercnic, profilePictureLink);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('uid', user.uid);
await user.sendEmailVerification();
Get.snackbar(
"Email Verification",
"Please verify your email",
snackPosition: SnackPosition.BOTTOM,
);
var bankDetails =
FirebaseFirestore.instance.collection('bankDetails').doc("1").get();
bankDetails.then((value) {
transactionController.setBankDetails(
value.data()!['bankName'],
value.data()!['accountNumber'],
value.data()!['accountTitle'],
value.data()!['bankBranch']);
}).catchError((error) {
throw (error);
});
}
Get.offAll(() => const LoginPage());
} on FirebaseAuthException catch (error) {
switch (error.code) {
case "user-not-found":
errorMessage = "Incorrect Email or Password";
break;
case "wrong-password":
errorMessage = "Incorrect Password";
break;
case "email-already-in-use":
errorMessage = "Email already in use";
break;
case "invalid-email":
errorMessage = "Email is not valid.";
break;
case "weak-password":
errorMessage = "Password should be at least 6 characters ";
break;
default:
errorMessage = error.code;
}
// Get.snackbar(errorMessage.tr, "Please Try Again.".tr,
// snackPosition: SnackPosition.BOTTOM);
generateError(errorMessage.tr, "Please Try Again.".tr);
}
}

You need to start by adding the lib
flutter pub add firebase_auth
then you need to make sure you installed firebase core and it's working from your app to firebase,
flutter pub add firebase_core
to init your firebase app, start by setting the options
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: ,
appId: ,
messagingSenderId: ,
projectId: ,
authDomain: ,
storageBucket: ,
measurementId: ,
);
and the initialization of your app
switch (defaultTargetPlatform) {
case TargetPlatform.windows:
_app = await desktop.Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
break;
default:
_app = await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform);
}
await Firebase.initializeApp();
and todo simple log in try
try {
final credential = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: emailAddress,
password: password,
);
} 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);
}
for more info please follow:
https://pub.dev/packages/fireflutter

Related

error : display a red line under this statement _userFromFirebaseUser(userCredential.user);

hi every one I'm trying making my app with flutter . it is contains a sign up page so I write the code and I'm retrieving an information from the firebase after I upload it .
the below code is the sign up code
UserModel? _userFromFirebaseUser(User userCredential) {
return userCredential != null
? UserModel(
id: userCredential.uid,
bannerImageUrl: '',
name: '',
email: '',
profileImageUrl: '')
: null;
}
Stream<UserModel?> get userCredential {
return auth
.authStateChanges()
.map((userCredential) => _userFromFirebaseUser(userCredential!));
}
Future SignUp(email, password) async {
var formdata = formstate.currentState;
if (formdata!.validate()) {
print("valid");
formdata.save();
try {
UserCredential userCredential =
(await auth.createUserWithEmailAndPassword(
email: myemail!, password: mypassword!));
FirebaseFirestore.instance
.collection('Users')
.doc(userCredential.user!.uid)
.set({'name': email, 'email': email});
_userFromFirebaseUser(userCredential.user);
return userCredential;
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
Navigator.of(context).pop();
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
Navigator.of(context).pop();
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
} else {}
}
and the red line appears on this line _userFromFirebaseUser(userCredential.user); as it is appears in the picture . please help me
userCredential.user is User? not User
change the method parameter
UserModel? _userFromFirebaseUser(User? userCredential) {
return ....
}

Flutter Connection State Management

Hello I am doing my fist App in Flutter and i am just setting up the authentication with FireBase, and a mistake its happenning. Im trying to manage the state and navigate between Home and Login with the streambuilder, and its working fine but only if i do a hot restart on Android Studio after registering a new user. After the hot reload it works fine, i am able to login with any of the existing users and it navigates to the home screen, and when i log out goes back to login screen, but if i create new user than just stops working, the screens do not alterate anymore when i log in with any of the old users...
here its my main
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(primaryColor: cPrimary),
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.active){
if(snapshot.hasData){
return Home_Screen();
} else if (snapshot.hasError){
return Center(child: Text('${snapshot.error}'),);
}
} else if (snapshot.connectionState == ConnectionState.waiting){
return Center(child: CircularProgressIndicator(color: cPrimary,));
}
return LoginScreen();
}
)
);
}
}
Here is my login and register functions
//Sign Up
Future <void> signUp({
required String email,
required String password,
required String username,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty && username.isNotEmpty){
UserCredential userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//add user to database
await _firestore.collection('users').doc(userCredential.user!.uid).set({
'username' : username,
'email' : email,
'uid' : userCredential.user!.uid,
});
}
} 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);
}
}
//Log In
Future <void> logIn({
required String email,
required String password,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty ){
UserCredential userCredential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);}
} 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 for that user.');
}
}
}
and here its how i am calling the functions on my screens
ElevatedButton(
onPressed: () async {
setState(() {
_isLoading = true;
});
await AuthService().logIn(
email: _emailController.text,
password: _passwordController.text,);
setState(() {
setState(() {
_isLoading = false;
});
});
},
ElevatedButton(
onPressed: () async {
setState(() {
_isLoading = true;
});
await AuthService().signUp(
email: _emailController.text,
password: _passwordController.text,
username: _usernameController.text,
);
setState(() {
_isLoading = false;
});
After creating the user account, ensure you log in as well.
//Sign Up
Future <void> signUp({
required String email,
required String password,
required String username,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty && username.isNotEmpty){
UserCredential userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//add user to database
await _firestore.collection('users').doc(userCredential.user!.uid).set({
'username' : username,
'email' : email,
'uid' : userCredential.user!.uid,
});
}
// add this
await logIn(email: email, password: password);
} 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);
}
}

Strange error using Flutter app + Deno + MongoDB backend

I want to write a simple registration function and this is my code:
auth_screen.dart:
Future<void> _submit() async {
if (!_formKey.currentState!.validate()) {
// Invalid!
return;
}
_formKey.currentState!.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
// Log user in
await Provider.of<Auth>(context, listen: false).login(
_authData['email'] as String,
_authData['password'] as String,
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'] as String,
_authData['password'] as String,
);
}
} on HttpException catch (error) {
var errorMessage = 'Authentication failed';
print("this is the auth data");
print(_authData);
if (error.toString().contains('EMAIL_EXISTS')) {
errorMessage = 'This email address is already in use.';
} else if (error.toString().contains('INVALID_EMAIL')) {
errorMessage = 'This is not a valid email address';
} else if (error.toString().contains('WEAK_PASSWORD')) {
errorMessage = 'This password is too weak.';
} else if (error.toString().contains('EMAIL_NOT_FOUND')) {
errorMessage = 'Could not find a user with that email.';
} else if (error.toString().contains('INVALID_PASSWORD')) {
errorMessage = 'Invalid password.';
}
_showErrorDialog(errorMessage);
} catch (error) {
var errorMessage = 'Could not authenticate you. Please try again later.' +
error.toString();
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
auth.dart:
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'register');
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
// final url = Uri.http('http://localhost:8000/api/', 'urlSegment');
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
//'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now().add(
Duration(
seconds: int.parse(
responseData['expiresIn'],
),
),
);
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode(
{
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate!.toIso8601String(),
},
);
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
This is the backend(Deno) part of the project:
auth_controller.ts:
async register(ctx: RouterContext) {
const { email, password } = await ctx.request.body().value;
let user = await User.findOne({ email });
if (user) {
ctx.response.status = 422;
ctx.response.body = { message: "Email is already exist" };
return;
}
const hashedPassword = hashSync(password);
user = new User({ email, password: hashedPassword });
await user.save();
ctx.response.status = 201;
ctx.response.body = {
id: user.id,
name: user.name,
email: user.email
};
}
And this is the user.ts class:
export default class User extends BaseModel {
public id: string = "";
public name: string = "";
public email: string = "";
public password: string = "";
constructor({ id = "", name = "", email = "", password = "" }) {
super();
this.id = id;
this.name = name;
this.email = email;
this.password = password;
}
static async findOne(params: object): Promise<User | null> {
const user = await userCollection.findOne(params);
if (!user) {
return null;
}
return new User(User.prepare(user));
}
async save() {
const _id = await userCollection.insertOne(this);
this.id = _id;
return this;
}
}
I get this error message when I want to test the application on Android emulator:
type 'Null' is not a subtype of type 'String'
When I try the backend server using Postman and send post request to http://0.0.0.0:8000/api/register address. I get correct response and it works, but I don't know why do I get Null response using the Flutter app?
I tried to print the variables in both front and backend side of the application and it seems they all are good and correct but I can not understand why do I get this error message?!
probably you got a null value in your map in this part since map return a null value when can't find a key, check if the Map value is not null
try {
if (_authMode == AuthMode.Login) {
// Log user in
await Provider.of<Auth>(context, listen: false).login(
_authData['email'] as String, // can return a null value
_authData['password'] as String, // can return a null value
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'] as String, // can return a null value
_authData['password'] as String, // can return a null value
);
}
}
Seems you're getting a null as a response value instead of a String.
EDIT:
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'register');
}
Check email and password are not null. And getting the correct values.
Actually the problem was from these two lines of code:
_token = responseData['idToken'];
_userId = responseData['localId'];
Because it wasn't passing these data in response from the backend side.

Flutter how to listen for email verification before user can sign in - firebase

My app allows the user to register and sends an email for verification. However i have a problem where the user can sign in with the new account whether the email is verified or not. I have looked and cannot find a solution to this bearing in mind i'm new to flutter
My Auth Code
Future<String> signIn(String email, String password) async {
AuthResult result = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
if (user.isEmailVerified) {
return user.uid;
} else {
return null;
}
}
Future<String> signUp(String email, String password) async {
AuthResult result = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
try {
await user.sendEmailVerification();
return user.uid;
} catch (e) {
print("An error occurred while trying to send email verification");
print(e.message);
}
}
sign in method
try {
if (_isLoginForm) {
userId = await widget.auth.signIn(_email, _password);
print('Signed in: $userId');
} else {
userId = await widget.auth.signUp(_email, _password);
//widget.auth.sendEmailVerification();
_showVerifyEmailSentDialog();
print('Signed up user: $userId');
}
setState(() {
_isLoading = false;
});
if (userId.length > 0 && userId != null && _isLoginForm) {
widget.loginCallback();
}

How to handle Platform Exception when sign-in flow cancelled by user

I am unable to handle the platform exception when user presses cancel instead of logging in using the google sign in window.
I have even tried an if statement so to not run if signIn returns null, but that does not work either.
Future<void> _handleSignIn() async {
try {
await googleSignIn.signIn();
} catch (error) {
print(error);
}
}
What's not so obvious when authenticating with google, is that the process consist of three steps
_googleSignIn.signIn() // prompt window
googleAccount.authentication // obtaining the credentials
_auth.signInWithCredential(credential) // the actual authentication
// STEP 1
// This is where flow gets cancelled and it results in the `googleAccount` to be null
GoogleSignInAccount googleAccount = await _googleSignIn.signIn();
if (googleAccount == null) {
return null;
}
// STEP 2
// obtaining credentials (cached or via input)
GoogleSignInAuthentication googleAuthentication = await googleAccount.authentication;
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleAuthentication.idToken,
accessToken: googleAuthentication.accessToken,
);
// STEP 3
// the provider authentication
AuthResult authResult = await _auth.signInWithCredential(credential);
FirebaseUser user = authResult.user;
// RESULT
print (user.uuid);
The issue I had and seem like others may have too, is that when wrapping three steps in try catch block and not handling the null value from the first step, and the catch block would expect the error object and code property - which would be the case. Anyways here is how I handle it now.
// https://github.com/flutter/flutter/issues/26705
Future<FirebaseUser> signInWithGoogle() async {
FirebaseUser user;
var errorMessage;
try {
GoogleSignInAccount googleAccount = await _googleSignIn.signIn();
if (googleAccount == null) {
errorMessage = "CANCELLED_SIGN_IN";
return Future.error(errorMessage);
}
GoogleSignInAuthentication googleAuthentication = await googleAccount.authentication;
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleAuthentication.idToken,
accessToken: googleAuthentication.accessToken,
);
AuthResult authResult = await _auth.signInWithCredential(credential);
user = authResult.user;
return user;
}
catch(error) {
switch (error.code) {
case "ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL":
errorMessage = "Account already exists with a different credential.";
break;
case "ERROR_INVALID_CREDENTIAL":
errorMessage = "Invalid credential.";
break;
case "ERROR_INVALID_EMAIL":
errorMessage = "Your email address appears to be malformed.";
break;
case "ERROR_WRONG_PASSWORD":
errorMessage = "Your password is wrong.";
break;
case "ERROR_USER_NOT_FOUND":
errorMessage = "User with this email doesn't exist.";
break;
case "ERROR_USER_DISABLED":
errorMessage = "User with this email has been disabled.";
break;
case "ERROR_TOO_MANY_REQUESTS":
errorMessage = "Too many requests. Try again later.";
break;
case "ERROR_OPERATION_NOT_ALLOWED":
errorMessage = "Signing in with Email and Password is not enabled.";
break;
default:
errorMessage = "An undefined Error happened. ";
}
}
if (errorMessage != null) {
return Future.error(errorMessage);
}
return null;
}
And the google button
GoogleSignInButton(
onPressed: () async {
var isError = false;
var authService = Provider.of<AuthService>(context, listen: false);
await authService.signInWithGoogle().catchError((errorMessage) async {
isError = true;
if (errorMessage != 'CANCELLED_SIGN_IN') {
await showPopup(context, title: 'Validation', child: Text(errorMessage));
}
});
if (isError == false) {
Navigator.pushReplacementNamed(context, HomeScreen.routeName);
}
},
),
You can simply catch Error like -
Future<void> _handleSignIn() async {
await googleSignIn.signIn().catchError((e) {
print(e);
});
}