Using Firebase Authentication

Once installed, you can access the firebase_auth plugin by importing it in your Dart code:

import 'package:firebase_auth/firebase_auth.dart';

Before using Firebase Auth, you must first have ensured you have initialized FlutterFire.

To create a new Firebase Auth instance, call the instance getter on FirebaseAuth:

FirebaseAuth auth = FirebaseAuth.instance;

By default, this allows you to interact with Firebase Auth using the default Firebase App used whilst installing FlutterFire on your platform. If however you'd like to use a secondary Firebase App, use the instanceFor method:

FirebaseApp secondaryApp = Firebase.app('SecondaryApp');
FirebaseAuth auth = FirebaseAuth.instanceFor(app: secondaryApp);

Authentication state

Firebase Auth provides many methods and utilities for enabling you to integrate secure authentication into your new or existing Flutter application. In many cases, you will need to know about the authentication state of your user, such as whether they're logged in or logged out.

Firebase Auth enables you to subscribe in realtime to this state via a Stream. Once called, the stream provides an immediate event of the user's current authentication state, and then provides subsequent events whenever the authentication state changes.

To subscribe to these changes, call the authStateChanges() method on your FirebaseAuth instance:

FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});

The stream returns a User class if the user is signed in, or null if they are not. You can read more about managing your users below.

If you need authentication state change events along with any user token refresh events, you can subscribe via the idTokenChanges() method instead.

Alternatively, if you need all user change events which also include authentication state changes and id token changes, you can subscribe via the userChanges() method. This stream provides realtime updates to the User class without having to call reload(), such as when credentials are linked, unlinked and when the user's profile is updated.

Persisting authentication state

The Firebase SDKs for all platforms provide out of the box support for ensuring that your user's authentication state is persisted across app restarts or page reloads.

On native platforms such as Android & iOS, this behaviour is not configurable and the user's authentication state will be persisted on-device between app restarts. The user can clear the apps cached data via the device settings which will wipe any existing state being stored.

On web platforms, the user's authentication state is stored in local storage. If required, you can change this default behaviour to only persist authentication state for the current session, or not at all. To configure these settings, call the setPersistence() method (note; on native platforms an UnimplementedError) will be thrown):

// Disable persistence on web platforms
await FirebaseAuth.instance.setPersistence(Persistence.NONE);

Sign-in methods

Firebase provides a number of ways to sign users into your application, from anonymous users, password authentication, phone authentication and using OAuth/social providers.

Before using any sign-in methods, ensure you have configured the sign-in methods on the Firebase console.

Anonymous sign-in

Even though many applications do not require the user to explicitly sign into an application, it is important that you are able to uniquely identify your users (for both analytical and security reasons). Anonymous sign-in provides an extra layer of security if using Firebase Firestore, Realtime Database or even an external API, since you're able to detect whether a request comes from an authenticated user.

If no previous anonymous account on the platform (for your specific application) has been created, when signing in anonymously Firebase will create a new unique user which will be persisted across app restarts/page reloads. If the user signs-out and reauthenticates anonymously again, they will be signed-in with the previously created account. It is however important to remember the anonymous account created will not be persisted if the user uninstalls the application, clears their browser storage or uses a private browsing method (e.g. incognito mode on Google Chrome).

To get started, call the signInAnonymously() method on the FirebaseAuth instance:

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

Once successfully resolved, the user will be granted an anonymous account. If you are listening to changes in authentication state, a new event will be sent to your listeners.

To learn more about how you can handle any errors which are thrown from the method, view the Error Handling documentation.

Email/Password Registration & Sign-in

Email/Password is a common user sign in method for most applications. This requires the user to provide an email address and secure password. Users can register new accounts with a method called createUserWithEmailAndPassword() or sign in to an existing account with signInWithEmailAndPassword().

Registration

To create a new account on your Firebase project call the createUserWithEmailAndPassword() method with the user's email address 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);
}

The method is a two-step operation; it will first create the new account (if it does not already exist and the password is valid) and then automatically sign in the user in to that account. If you are listening to changes in authentication state, a new event will be sent to your listeners.

To learn more about how you can handle any errors which are thrown from the method, view the Error Handling documentation.

Sign-in

To sign-in to an existing account, call the 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.');
}
}

Once successful, if you are listening to changes in authentication state, a new event will be sent to your listeners.

Verifying a users email

Even though the above authentication flows sign a user into your application, they can provide any valid email address even if they do not have access to that email address. In many cases, you may wish to make a user verify the provided email address before you grant them full access to your application.

The User class provides a sendEmailVerification() method and emailVerified property which you can use to handle this scenario.

For example, once signed in you can check the property and send an email verification to the user:

User user = FirebaseAuth.instance.currentUser;
if (!user.emailVerified) {
await user.sendEmailVerification();
}

Firebase will send an automated email to the user with a unique code. This code can then be entered via the applyActionCode() method. You can first check whether the code is valid by using the checkActionCode() method:

FirebaseAuth auth = FirebaseAuth.instance;
// Get the code from the email:
String code = 'xxxxxxx';
try {
await auth.checkActionCode(code);
await auth.applyActionCode(code);
// If successful, reload the user:
auth.currentUser.reload();
} on FirebaseAuthException catch (e) {
if (e.code == 'invalid-action-code') {
print('The code is invalid.');
}
}

To learn more about how you can handle any errors which are thrown from the method, view the Error Handling documentation.

Email Link Authentication

You can use Firebase Authentication to sign in a user by sending them an email containing a link, which they can click to sign in. In the process, the user's email address is also verified.

Enable Email Link sign-in for your Firebase project

Ensure that passwordless sign-in is enabled in the project. Follow the guide here.

Send an authentication link to the user's email address

To initiate the authentication flow, present the user with an interface that prompts the user to provide their email address and then call sendSignInLinkToEmail to request that Firebase send the authentication link to the user's email.

Construct the ActionCodeSettings object, which provides Firebase with instructions on how to construct the email link. Set the following fields:

  • url: The deep link to embed and any additional state to be passed along. The link's domain has to be whitelisted in the Firebase Console list of authorized domains, which can be found by going to the Sign-in method tab (Authentication -> Sign-in method). The link will redirect the user to this URL if the app is not installed on their device and the app was not able to be installed.

  • androidPackageName and IOSBundleId: The apps to use when the sign-in link is opened on an Android or iOS device. Learn more on how to configure Firebase Dynamic Links to open email action links via mobile apps.

  • handleCodeInApp: Set to true. The sign-in operation has to always be completed in the app unlike other out of band email actions (password reset and email verifications). This is because, at the end of the flow, the user is expected to be signed in and their Auth state persisted within the app.

  • dynamicLinkDomain: When multiple custom dynamic link domains are defined for a project, specify which one to use when the link is to be opened via a specified mobile app (for example, example.page.link). Otherwise the first domain is automatically selected.

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 the authentication link to the user's email, and save the user's email in case the user completes the email sign-in on the same device.

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

Verify email link and sign in

Firebase Authentication uses Firebase Dynamic Links to send the email link to a mobile device. For sign-in completion via mobile application, the application has to be configured to detect the incoming application link, parse the underlying deep link and then complete the sign-in.

Follow the setup process for Firebase Dynamic Links on Flutter in this guide.

After you received the link, verify that it is meant for email link authentication and complete the sign in.

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)
.catchError(
(onError) => print('Error signing in with email link $onError'))
.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!');
});
}

Signing Out

To sign a user out, call the signOut() method:

await FirebaseAuth.instance.signOut();

If you are listening to changes in authentication state, a new event will be sent to your listeners.

Other sign-in methods

Firebase also supports authenticating with external provides. To learn more, view the documentation for your authentication method:

User management

Once authenticated, FlutterFire provides you access to the user via the User class. The class stores the current information about the user such as their unique user ID, any linked provider accounts and methods to manage the user.

The User class is returned from any authentication state listeners, or as part of a UserCredential when using authentication methods. If you are sure the user is currently signed-in, you can also access the User via the currentUser property on the FirebaseAuth instance. The examples below show how to access the user:

FirebaseAuth auth = FirebaseAuth.instance;
if (auth.currentUser != null) {
print(auth.currentUser.uid);
}

Deleting a user

If your user wishes to delete their account from your project, this can be archived with the delete() method. Since this is a security-sensitive operation, it requires that user must have recently signed-in. You can handle this scenario by catching the error, for example:

try {
await FirebaseAuth.instance.currentUser.delete();
} catch on FirebaseAuthException (e) {
if (e.code == 'requires-recent-login') {
print('The user must reauthenticate before this operation can be executed.');
}
}

Reauthenticating a user

As mentioned above, some operations such as deleting the user, updating their email address or providers require the user to have recently signed in. Rather than signing the user out and back in again, the reauthenticateWithCredential() method can be called. If a recent login is required, create a new AuthCredential and pass it to the method. For example, to reauthenticate with email & password, create a new EmailAuthCredential:

// Prompt the user to enter their email and password
String email = 'barry.allen@example.com';
String password = 'SuperSecretPassword!';
// Create a credential
EmailAuthCredential credential = EmailAuthProvider.credential(email: email, password: password);
// Reauthenticate
await FirebaseAuth.instance.currentUser.reauthenticateWithCredential(credential);

Reauthentication also works if you are using an OAuth credential instead.

Linking user accounts

You can allow your users to sign into your application using multiple providers by linking authentication credentials to existing user accounts. Users can then be identified using their Firebase UID, regardless of the provider they used to sign in.

The user must first be logged in to one of the accounts you want to link the new provider to. You can then log the user into the second provider, and pass that AuthCredential to the linkWithCredential method from the first UserCredential:

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