Firebase Auth (Java)

Every recipe app eventually needs the question "whose recipe is this?" answered. Firebase Authentication gives RecipeBox a ready-made user account system — sign-up, sign-in, session handling — without building and hosting a custom auth backend of our own.

Enabling Email/Password Sign-In

In the Firebase Console, open Authentication → Sign-in method and enable the Email/Password provider. This is a one-time console setting — no extra Gradle dependency beyond firebase-auth, already pinned by the BoM from Setup & Analytics:

dependencies {
    implementation platform('com.google.firebase:firebase-bom:33.1.2')
    implementation 'com.google.firebase:firebase-auth'
}

Creating a New Account

private void registerAccount(String email, String password) {
    FirebaseAuth.getInstance()
        .createUserWithEmailAndPassword(email, password)
        .addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
                Log.d("Auth", "Account created, uid=" + user.getUid());
                goToRecipeList();
            } else {
                Log.w("Auth", "Sign-up failed", task.getException());
                showError(task.getException().getMessage());
            }
        });
}
The Task API, explained:
  • createUserWithEmailAndPassword() doesn't block or return a result directly — it returns a Task<AuthResult> immediately and does the network work in the background.
  • addOnCompleteListener(task -> { ... }) is the callback that fires once that background work finishes, whether it succeeded or failed.
  • task.isSuccessful() tells you which branch you're in; task.getException() gives the failure reason (e.g. "email already in use", "weak password") when it isn't.
  • This callback-based Task pattern is Firebase's standard shape for every asynchronous Java call in this section — the same pattern reappears for sign-in, Firestore reads/writes, and more.
If you've seen the Kotlin track: Kotlin code often bridges these same Task objects with a suspend-friendly .await() extension, letting a coroutine await the result instead of nesting a listener. Java doesn't have coroutines, so the listener-based callback shown here is the standard, idiomatic way to consume Firebase's Java API.

Signing In an Existing User

private void login(String email, String password) {
    FirebaseAuth.getInstance()
        .signInWithEmailAndPassword(email, password)
        .addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                goToRecipeList();
            } else {
                showError("Invalid email or password");
            }
        });
}

Checking the Current User & Observing State

To decide whether to show a login screen or go straight to the recipe list, check for a signed-in user at startup:

FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
if (currentUser != null) {
    goToRecipeList();
} else {
    goToLoginScreen();
}

For ongoing changes — sign-in, sign-out, token refresh — attach an AuthStateListener:

private final FirebaseAuth.AuthStateListener authListener = firebaseAuth -> {
    FirebaseUser user = firebaseAuth.getCurrentUser();
    if (user != null) {
        Log.d("Auth", "Signed in as " + user.getUid());
    } else {
        Log.d("Auth", "Signed out");
    }
};

@Override
protected void onStart() {
    super.onStart();
    FirebaseAuth.getInstance().addAuthStateListener(authListener);
}

@Override
protected void onStop() {
    super.onStop();
    FirebaseAuth.getInstance().removeAuthStateListener(authListener);
}

Signing Out

FirebaseAuth.getInstance().signOut();
// AuthStateListener fires again here, now with getCurrentUser() == null

Other Sign-In Providers

Email/password is the simplest starting point, but Firebase Auth supports several other providers behind the same FirebaseAuth API — most notably Google Sign-In (one-tap sign-in using the user's existing Google account) and phone number authentication (an SMS verification code in place of a password). Both plug into the same account system; only the initial credential step differs.

Once a user is signed in, their FirebaseUser.getUid() becomes the key that ties them to their own data — that's exactly how we'll scope each user's saved recipes to just them in Cloud Firestore (Java).