Firebase Authentication: Email, Google, and Apple Sign-In
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.