Skip to main content

firebase_auth

PackageKindProvides the roleNeedsChoose with
smf_firebase_authinfrastructureAuthenticationfirebase_core-m firebase_auth

firebase_auth signs the users of the app in with Firebase Authentication, through the firebase_auth package: with an email address and a password, and as anonymous users.

The module brings the service and no screens. The screens of sign-in are the feature sign_in, which requires a module such as this one. The code of the app signs in, up and out through appSession, which the auth role generates; see Sign-in.

What it adds to the app​

In the appWhat it is
firebase_auth: ^6.7.0 in the dependenciesThe package of Firebase Authentication.
lib/core/auth/firebase_auth_service.dartFirebaseAuthService, the sign-in service of the app on FirebaseAuth.instance.
tool/enable_firebase_sign_in.dartThe script that enables the ways to sign in in the Firebase project.
The section "Firebase Authentication" of the READMEHow the ways to sign in are enabled, with the script and in the Firebase console.

Whichever module provides it, the auth role adds three files in lib/core/auth/:

FileWhat it holds
app_session.dartappSession, which tells who uses the app and through which code signs in, up and out, authMode, the mode of the app, and initAuth().
auth_service.dartAuthService, the interface that this module implements, and AuthFailure with its reasons.
guest_data.darttakeGuestData(), which you edit: what an anonymous user has when they sign in to an account that exists already.

In its platform phase, bootstrap() initializes Firebase and then starts the session. This is bootstrap() of an app with this module alone:

lib/bootstrap.dart
Future<void> bootstrap() async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await initAuth();
}

Firebase keeps the user on the device and hands that user over when it is initialized. So the service is created without waiting and has the user at once, and the app knows who is signed in before its first frame.

In the guide for coding agents of the app, the auth role describes the session under "Authentication". The module adds which file is on Firebase Authentication, where a code of Firebase gets its reason, that the ways to sign in are enabled in the Firebase project, and that an agent runs the script that enables them only when asked.

Enable the ways to sign in​

The ways to sign in are enabled in the Firebase project, not in the code:

  • Email/Password, in every mode of the app;
  • Anonymous, when the mode of the app is anonymous.

The script of the app enables those that the mode of the app needs, with the Firebase CLI 15.6.0 or later:

dart tool/enable_firebase_sign_in.dart

In a terminal, smf create offers to run it right after flutterfire configure configured the app. It asks first, because the Firebase CLI adds a web app named "Default Web App" to a project that has none. The Firebase console enables the methods without it, under Authentication > Sign-in method of the project that the app is configured for.

The script reads the project from firebase.json and the mode from authMode of the app, never disables a method, and changes no file of the app. Run it again for another project, or after you changed the mode to anonymous. Firebase describes the question, what the script does and its arguments, such as --project <id> and --account <email>.

Until the ways to sign in are enabled, signing in and signing up fail with the reason notConfigured, and the developerHint of the failure tells both ways:

AuthFailure: notConfigured (Sign-in is not enabled in the Firebase project my-project (Firebase answered operation-not-allowed). To fix it, run `dart tool/enable_firebase_sign_in.dart` in the directory of the app, or enable Email/Password, and Anonymous for an app that signs in anonymous users, in the Firebase console under Authentication > Sign-in method: https://console.firebase.google.com/project/my-project/authentication/providers)

In the mode anonymous, the app also starts without a user until Anonymous is enabled.

Before it generates the app, SMF checks the machine for a Firebase CLI that has the command, as "Firebase CLI 15.6.0 or later". The check only warns. With an older Firebase CLI, the run tells how to update it and prints the command of the script for later.

The reasons of a failure​

A call of appSession fails only with an AuthFailure, whose reason the app shows a text for. The service gives each code of Firebase its reason, in _failureOf() of its file:

ReasonCodes of Firebase
invalidCredentialsinvalid-credential, invalid-login-credentials, wrong-password, user-not-found
emailInUseemail-already-in-use, credential-already-in-use
weakPasswordweak-password, password-does-not-meet-requirements
invalidEmailinvalid-email, missing-email
userDisableduser-disabled
tooManyAttemptstoo-many-requests
networknetwork-request-failed
recentSignInRequiredrequires-recent-login
notConfiguredoperation-not-allowed, admin-restricted-operation, and any code whose message has CONFIGURATION_NOT_FOUND
unknownAny other code. The developerHint has the code and the message of Firebase on one line.

Two cases need more than the code:

  • Firebase tells of a project in which Authentication was never set up only in a message: that of an unknown error on Android, and that of an internal error on iOS, where the message is the description of the error over many lines. The service finds CONFIGURATION_NOT_FOUND there and answers notConfigured. The hint names the code and CONFIGURATION_NOT_FOUND, and leaves the description out.
  • On iOS and macOS, Firebase may answer for such a project with an internal error whose message says no more. Nothing tells it from another internal error, so the service answers notConfigured there too, with a hint that says that it may be another error.

A code that the service does not know becomes unknown. To give it a reason, add it to _failureOf().

What the service adds to the package​

The auth role promises more than the package does in a few places, and the service makes up the difference:

What the service doesWhy
An empty address or password fails before Firebase is asked. An empty address is invalidEmail. An empty password is invalidCredentials in a sign-in, and weakPassword in a sign-up.Android refuses an empty text with a code that has no reason, and iOS answers an empty password as a wrong one.
A user has no address when Firebase has an empty one.Android has an empty address, not none, for an anonymous user whom it kept on the device.
It signs out after it deleted a user.The package keeps a deleted user as its current one until the platform tells it of the sign-out.
A call for the user who is signed in, such as the deletion of the account, signs that user out first when the session of the user has ended on the server, and fails with recentSignInRequired. Firebase answers such a call with user-token-expired, invalid-user-token, user-not-found or no-current-user.A session ends on the server when the account is deleted, or its password changed, on another device.
A password reset completes when Firebase answers user-not-found.A project without the protection against the enumeration of email addresses tells that an address has no account, and the app should not.
It tells of the user after each of its calls and when Firebase tells of a change, each time with the user that it has when a listener hears of it.A listener then never hears of a user who is not the current one any more.

The service is the same in every mode of the app.

The message of a password reset​

Firebase sends the message with which a user sets a new password from a template of the project: Authentication > Templates in the Firebase console.

The module uses the localization role. In an app with it, the service gives Firebase the language that the app is in before it asks for the message: the language that the user chose, or the one that the device prefers among those of the app.

lib/core/auth/firebase_auth_service.dart
    // The message is in the language that the app is in.
await _auth.setLanguageCode(
(appLocale.value ??
basicLocaleListResolution(
WidgetsBinding.instance.platformDispatcher.locales,
appLocales,
))
.languageCode,
);

In an app without the role, the service sets no language.

Anonymous users​

In the mode anonymous, the app signs in an anonymous user when it starts, and signing up gives that same user the account. While an anonymous user is signed in, Firebase answers a further anonymous sign-in with that user and creates no other.

When an anonymous user signs in to an account that exists already, the anonymous user stays in the Firebase project, and nobody can sign in as that user again. A project that is upgraded to Firebase Authentication with Identity Platform can delete anonymous users that are older than 30 days automatically; see Automatic clean-up in the documentation of Firebase. What the app itself keeps under the id of the anonymous user moves as takeGuestData() says; see the data of a guest.

In tests​

A test that runs main() or bootstrap() starts Firebase, which needs the options of flutterfire configure and a mock of its platform side, and the firebase_auth plugin brings no mock of its own platform side for tests. A test of a screen needs neither: it gives appSession.start() a service of its own; see Sign-in.

SMF's CI checks the service on the real firebase_auth package, over a stand-in for its platform side that answers the messages of the plugin: what each call sends to Firebase, the reason for each code as Android and iOS send it, and the user whom a start finds on the device. On devices it checks that the session of the app has the user that the plugin has. See Contributing.

Choosing it​

smf create asks which module provides the authentication of the app, and offers None as well. With a provider chosen, it then asks who may use the app without an account. To choose both without the questions:

smf create my_app -m firebase_auth --auth-mode guest

firebase_core comes with the module:

Adding firebase_core: a dependency of firebase_auth.
Adding flutter_core: the only provider of the app entry role, which every app needs.

The feature sign_in requires the role that this module provides, so -m sign_in brings the module too while it is the only one that provides sign-in.

After generation, firebase_core asks whether to run flutterfire configure, as for every app with Firebase, and this module then asks whether to enable the ways to sign in; see Firebase.