Pages

Firebase Authentication in Flutter

First and foremost, download and install Firebase SDKs for Flutter, in case you haven’t installed it yet. 


Once initialized, import firebase_auth  plugin in your Flutter Dart code and get access to it. 

import 'package:firebase_auth/firebase_auth.dart';


Once installed, make sure that you have initialized FlutterFire. If not follow the below code.


Now, in order to create a new Firebase Auth instance, use the instance getter on FirebaseAuth:

FirebaseAuth auth = FirebaseAuth.instance;


Calling instance will enable you to interact with Firebase Auth by using the Firebase App during the installation of FireFlutter on your system. In case, you want to use a different Firebase App, call instanceFor method:

FirebaseApp secondaryApp = Firebase.app('SecondaryApp');

FirebaseAuth auth = FirebaseAuth.instanceFor(app: secondaryApp);

Authentication state

For integrating secure authentication into the new or existing Flutter app, FirebaseAuth is necessary as it provides many utilities and methods. Many times you also need to check the Firebase authentication state of your user account in Flutter, for example, whether the user is logged in or logged out. 


There are three ways for listening to authentication state changes: 

  1. authStateChanges()

 Use authStateChanges() method on your FirebaseAuth to make these changes.

FirebaseAuth.instance

  .authStateChanges()

  .listen((User? user) {

    if (user == null) {

      print('User is currently signed out!');

    } else {

      print('User is signed in!');

    }

  });


Events are signals fired on the below changes:

  • When the listener is registered

  • When a user signs in

  • When an existing user signs out.


  1. idTokenChanges()

Use idTokenChanges() method on your FirebaseAuth instance to see the changes:

FirebaseAuth.instance

  .idTokenChanges()

  .listen((User? user) {

    if (user == null) {

      print('User is currently signed out!');

    } else {

      print('User is signed in!');

    }

  });


Events are signals fired on the below changes

  • When the listener is registered

  • When a user signs in

  • When an existing user signs out.

  • When the existing user’s token is changed.


Warning: If you are setting custom claims from your firebase admin SDK implementation, you will come across the event fire when the below changes occur:


  • A user re-authenticate or signs in after custom claims modification. 

  • A current user refreshes their ID token after the old ID token expires. 

  • When a user forced refreshed its ID token by using FirebaseAuth.instance.currentUser.getIdTokenResult(true)  


  1. userChange()

Use userChange() method on FirebaseAuth instance to get these changes:

FirebaseAuth.instance

  .userChanges()

  .listen((User? user) {

    if (user == null) {

      print('User is currently signed out!');

    } else {

      print('User is signed in!');

    }

  });


Events are signals fired when the below changes occur:

  • When the listener is registered

  • When a user signs in

  • When an existing user signs out.

  • When the existing user’s token is changed.

  • When FirebaseAuth.instance.currentUser calls the below-mentioned methods.

                  reload()

                  unlink()

                  updateEmail()

                  updatePassword()

                   updatePhoneNumber()

                   updateProfile()


Persisting Authentication State

Persistence authentication remains across app pages because Firebase SDK provides strong support for a systematic authentication state.  On native devices like iOS and Android, the behaviors would not be visible and the persistent authentication state will be visible on-device between application restarts. 


On the web platform, the authentication state is visible in local storage. You can change this situation to persist authentication state by configuring the settings. Call setPersistence() method to see the change. 

// Disable persistence on web platforms

await FirebaseAuth.instance.setPersistence(Persistence.NONE);

Sign-in methods

Firebase Authentication on Flutter has provided many methods to sign in to your apps, from the unknown username, phone authentication, password authentication, and using social providers.  


Before signing in with any method make sure that you configure sign-in methods on the Firebase Authentication console. 

Anonymous sign-in

Anonymous sign-in is the best way to analyze your users and ensure the safety and security of your application. This method will provide your application with a layer of security if they use an external API, Realtime Database, or Firebase Firestore. 


Use signInAnonymously() method on FirebaseAuth instance to see this change.  

UserCredential userCredential = await FirebaseAuth.instance.signInAnonymously();


If you want to learn about error handling, go for error handling documentation to understand it better. 


Email/Password Sign-in

With the help of this method, you can get the email address and secured password to sign in to your application. Users can create accounts with the help of createUserWithEmailAndPassword() or if they have an existing account they can sign in with signInWithEmailAndPassword()

Registration

The below code will help you create a user’s new account and get your email id and password. 

try {

  UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(

    email: "barry.allen@example.com",

    password: "SuperSecretPassword!"

  );

} 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 the existing account sign-in method use the following code.

try {

  UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(

    email: "barry.allen@example.com",

    password: "SuperSecretPassword!"

  );

} 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.');

  }

}

Sign-in 

To sign in to the current user’s account, use signInWithEmailAndPassword() method:

try {

  UserCredential userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(

    email: "barry.allen@example.com",

    password: "SuperSecretPassword!"

  );

} 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.');

  }

}

Verify users email

This method will help you get the authentic email address that is actively used by the user. The above-mentioned authentication does not make for verification detail. Users can provide email addresses that they might not be using actively. 


The below Flutter authentication example will help you handle this scenario. 

User? user = FirebaseAuth.instance.currentUser;


if (user!= null && !user.emailVerified) {

  await user.sendEmailVerification();

}

Firebase will send users an automated email along with a link. Users can verify email by opening a link to a browser. 

Open the link in the app

This condition will allow the user to get back to the app once they have verified their email id address. Plus, you can also specify whether you want to handle email action via application or from a web page.

User? user = FirebaseAuth.instance.currentUser;


if (user != null && !user.emailVerified) {

  var actionCodeSettings = ActionCodeSettings(

      url: 'https://www.example.com/?email=${user.email}',

      dynamicLinkDomain: 'example.page.link',

      androidPackageName: 'com.example.android',

      androidInstallApp: true,

      androidMinimumVersion: '12',

      iOSBundleId: 'com.example.ios',

      handleCodeInApp: true,

  );


  await user.sendEmailVerification(actionCodeSettings);

}


Now the code is received in an application by parsing Firebase Dynamic link. 

FirebaseAuth auth = FirebaseAuth.instance;


//Get actionCode from the dynamicLink

final Uri deepLink = dynamicLink?.link;

var actionCode = deepLink.queryParameters['oobCode'];


try {

  await auth.checkActionCode(actionCode);

  await auth.applyActionCode(actionCode);


  // If successful, reload the user:

  auth.currentUser.reload();

} on FirebaseAuthException catch (e) {

  if (e.code == 'invalid-action-code') {

    print('The code is invalid.');

  }

}

Email Link Authentication

Send an authentication link to the email of the user

You will be using URL, android package name and IOSBundleId, handleCodeInApp, and dynamicLinkDomain

var acs = ActionCodeSettings(

    // URL you want to redirect back to. The domain (www.example.com) for this

    // URL must be whitelisted in the Firebase Console.

    url: 'https://www.example.com/finishSignUp?cartId=1234',

    // This must be true

    handleCodeInApp: true,

    iOSBundleId: 'com.example.ios',

    androidPackageName: 'com.example.android',

    // installIfNotAvailable

    androidInstallApp: true,

    // minimumVersion

    androidMinimumVersion: '12');


  • Ask the user for their email

Send and verify the authentication link to the email of a user and save their email once they complete signing in. 

var emailAuth = 'someemail@domain.com';

FirebaseAuth.instance.sendSignInLinkToEmail(

        email: emailAuth, actionCodeSettings: acs)

    .catchError((onError) => print('Error sending email verification $onError'))

    .then((value) => print('Successfully sent email verification'));

});


Verification of email link and sign in

With the help of Firebase Dynamic Link in Flutter, Firebase Authentication can send an email link to a user’s mobile app. In order to complete the sign-in process through mobile, the app must detect the incoming link to an app, parse the underlying deep link, and then complete the sign-in process. 

var auth = FirebaseAuth.instance;

// Retrieve the email from wherever you stored it

var emailAuth = 'someemail@domain.com';

// Confirm the link is a sign-in with email link.

if (auth.isSignInWithEmailLink(emailLink)) {

  // The client SDK will parse the code from the link for you.

  auth.signInWithEmailLink(email: emailAuth, emailLink: emailLink).then((value) {

    // You can access the new user via value.user

    // Additional user info profile *not* available via:

    // value.additionalUserInfo.profile == null

    // You can check if the user is new or existing:

    // value.additionalUserInfo.isNewUser;

    var userEmail = value.user;

    print('Successfully signed in with email link!');

  }).catchError((onError) {

    print('Error signing in with email link $onError');

  });

}

Signing out

Call signOut() method for a user sign-out.

await FirebaseAuth.instance.signOut();


Whether you want Google Firebase Authentication in the Flutter app or another source of authentication, you can develop any of them. 


Some other sign-in methods are as follows:

  • Phone number sign-in

  • Facebook sign-in

  • Twitter sign-in

  • Google sign-in

  • Apple sign-in

 

User management

Once you have authenticated the email address, FlutterFire will enable you to access the user through the user class. The user class is then returned from any of the authentication state listeners, in the form of usercredentials while using authentication methods. 


For currentUser state:

var currentUser = FirebaseAuth.instance.currentUser;


if (currentUser != null) {

  print(currentUser.uid);

}


For Sign-in methods:

UserCredential userCredential = await FirebaseAuth.instance.signInAnonymously();


print(userCredential.user!.uid);


For State Listener Stream:

FirebaseAuth.instance

  .authStateChanges()

  .listen((User? user) {

    if (user != null) {

      print(user.uid);

    }

  });

 

Deleting a user

In case your user wants to delete their account from the app or project, you need to call delete() method. 

try {

  await FirebaseAuth.instance.currentUser!.delete();

} on FirebaseAuthException catch (e) {

  if (e.code == 'requires-recent-login') {

    print('The user must reauthenticate before this operation can be executed.');

  }

}


Reauthenticating a user

Some processes like updating the email address, generating a new password, or re-registring an account must be reauthenticated by the application. In order to do that, you need to call reauthenticateWithCredential() on Firebase Authentication. 

// Prompt the user to enter their email and password

String email = 'barry.allen@example.com';

String password = 'SuperSecretPassword!';


// Create a credential

AuthCredential credential = EmailAuthProvider.credential(email: email, password: password);


// Reauthenticate

await FirebaseAuth.instance.currentUser!.reauthenticateWithCredential(credential);


This authentication process will also work by using OAuth credentials. 


Linking user's registered accounts

This method will allow your user to register with multiple providers and link all the credentials with the existing account. The linking method will help users identify with Firebase User ID, regardless of any sign-in account. Use the below code to generate the Flutter Firebase login system.  

Future<void> linkGoogleAndTwitter() async {

  // Trigger the Google 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 googleCredential = GoogleAuthProvider.credential(

    accessToken: googleAuth.accessToken,

    idToken: googleAuth.idToken,

  );

  // Sign in to Firebase with the Google [UserCredential].

  final UserCredential googleUserCredential =

    await FirebaseAuth.instance.signInWithCredential(googleCredential);


  // Now let's link Twitter to the currently signed in account.

  // Create a [TwitterLogin] instance.

  final TwitterLogin twitterLogin = new TwitterLogin(

    consumerKey: consumerKey,

    consumerSecret: consumerSecret

  );

  // Trigger the sign-in flow.

  final TwitterLoginResult loginResult = await twitterLogin.authorize();

  // Get the logged in session.

  final TwitterSession twitterSession = loginResult.session;

  // Create a [AuthCredential] from the access token.

  final AuthCredential twitterAuthCredential =

    TwitterAuthProvider.credential(

      accessToken: twitterSession.token,

      secret: twitterSession.secret

     );

  // Link the Twitter account to the Google account.

  await googleUserCredential.user.linkWithCredential(twitterAuthCredential);

}


Emulator Usage

In case you are using a local emulator then you will able to connect using the useAuthEmulator method. Make sure that you have connected your networks to the emulator in an application. 

Future<void> main() async {

  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp();


  // Ideal time to initialize

  await FirebaseAuth.instance.useAuthEmulator('localhost', 9099);

  //...

}


No comments:

Post a Comment

Make new Model/Controller/Migration in Laravel

  In this article, we have included steps to create a model and controller or resource controller with the help of command line(CLI). Here w...