← Articles

Firebase Authentication: Email, Google, and Apple Sign-In

By Mark · 29 June 20260 views

Firebase Authentication: Email, Google, and Apple Sign-In

Authentication is the gateway to your app. Get it wrong and users bounce at the sign-up screen; get it right and you earn trust before they even see your features. Firebase Authentication handles the complexity of credential management, token refresh, and multi-provider linking so you can focus on building your app. This guide covers implementing email/password, Google Sign-In, and Sign In with Apple in Flutter.

Project Setup

Add the required packages to pubspec.yaml:

dependencies:
  firebase_core: ^3.0.0
  firebase_auth: ^5.0.0
  google_sign_in: ^6.2.0
  sign_in_with_apple: ^6.1.0

Initialize Firebase in main.dart:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

Auth State Stream

Before building any sign-in UI, wire up an auth state listener. This stream emits a User? whenever the signed-in user changes:

StreamProvider<User?>.autoDispose((ref) {
  return FirebaseAuth.instance.authStateChanges();
})

Use this provider to gate navigation: unauthenticated users see the sign-in screen, authenticated users go directly to the home screen.

Email and Password

class AuthService {
  final _auth = FirebaseAuth.instance;

  Future<UserCredential> signUpWithEmail(
    String email,
    String password,
  ) async {
    return _auth.createUserWithEmailAndPassword(
      email: email,
      password: password,
    );
  }

  Future<UserCredential> signInWithEmail(
    String email,
    String password,
  ) async {
    return _auth.signInWithEmailAndPassword(
      email: email,
      password: password,
    );
  }

  Future<void> sendPasswordReset(String email) async {
    await _auth.sendPasswordResetEmail(email: email);
  }

  Future<void> signOut() async {
    await _auth.signOut();
  }
}

Always send a verification email after sign-up:

final credential = await authService.signUpWithEmail(email, password);
await credential.user?.sendEmailVerification();

Google Sign-In

Future<UserCredential?> signInWithGoogle() async {
  final googleUser = await GoogleSignIn().signIn();
  if (googleUser == null) return null; // User cancelled

  final googleAuth = await googleUser.authentication;
  final credential = GoogleAuthProvider.credential(
    accessToken: googleAuth.accessToken,
    idToken: googleAuth.idToken,
  );

  return FirebaseAuth.instance.signInWithCredential(credential);
}

For iOS, add your GoogleService-Info.plist to the Runner target and add the reversed client ID to your URL schemes in Info.plist. For Android, add your SHA-1 fingerprint to the Firebase project settings.

Sign In with Apple

Apple requires SHA-256 hashing of the nonce for security:

Future<UserCredential> signInWithApple() async {
  final rawNonce = generateNonce();
  final nonce = sha256ofString(rawNonce);

  final appleCredential = await SignInWithApple.getAppleIDCredential(
    scopes: [AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName],
    nonce: nonce,
  );

  final oauthCredential = OAuthProvider('apple.com').credential(
    idToken: appleCredential.identityToken,
    rawNonce: rawNonce,
  );

  return FirebaseAuth.instance.signInWithCredential(oauthCredential);
}

Apple only sends the user's name and email on the very first sign-in. Store these in Firestore during that first sign-in, because subsequent sign-ins will not include them.

Linking Multiple Providers

A user might sign up with email and later want to add Google. Firebase supports linking:

Future<void> linkGoogleToCurrentUser() async {
  final googleUser = await GoogleSignIn().signIn();
  final googleAuth = await googleUser!.authentication;
  final credential = GoogleAuthProvider.credential(
    accessToken: googleAuth.accessToken,
    idToken: googleAuth.idToken,
  );
  await FirebaseAuth.instance.currentUser?.linkWithCredential(credential);
}

Error Handling

Firebase Auth errors come as FirebaseAuthException with a code property:

try {
  await authService.signInWithEmail(email, password);
} on FirebaseAuthException catch (e) {
  final message = switch (e.code) {
    'user-not-found'    => 'No account found for this email.',
    'wrong-password'    => 'Incorrect password.',
    'too-many-requests' => 'Too many attempts. Try again later.',
    _                   => 'Sign-in failed. Please try again.',
  };
  showErrorSnackbar(message);
}

Security Rules

Firebase Authentication integrates directly with Firestore security rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Conclusion

Firebase Authentication gives you a production-grade auth system with minimal code. The auth state stream is the backbone — build your navigation and UI reactively on top of it, and the rest falls into place naturally. Support all three providers (email, Google, Apple) from day one: Apple Sign-In is required by App Store guidelines for any app offering third-party login, and Google Sign-In dramatically lowers sign-up friction on Android.

Sign in to like, dislike, or report.

Comments

No comments yet. Be the first!

Sign in to leave a comment.

Firebase Authentication: Email, Google, and Apple Sign-In — ANN Tech