Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when setting up auth, managing auth state, implementing email/password or social sign-in, handling auth errors, or managing users.
.claude/skills/evanca-firebase-auth/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 47% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 53% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 38% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 39% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 70% | 0% |
This skill defines how to correctly use Firebase Authentication in Flutter applications.
Use this skill when:
recaptcha-sdk-not-linked for phone auth).flutter pub add firebase_authdartimport 'package:firebase_auth/firebase_auth.dart';
Local emulator for testing:
dartFuture<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); await FirebaseAuth.instance.useAuthEmulator('localhost', 9099); // ... }
Use the appropriate stream based on what you need to observe:
| Stream | Fires when | |---|---| | authStateChanges() | User signs in or out | | idTokenChanges() | ID token changes (including custom claims) | | userChanges() | User data changes (e.g., profile updates) |
dartFirebaseAuth.instance .authStateChanges() .listen((User? user) { if (user == null) { print('User is currently signed out!'); } else { print('User is signed in!'); } });
Create a new account:
darttry { final credential = await FirebaseAuth.instance.createUserWithEmailAndPassword( email: emailAddress, password: password, ); } 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); }
Sign in:
darttry { final credential = await FirebaseAuth.instance.signInWithEmailAndPassword( email: emailAddress, password: password, ); } on FirebaseAuthException catch (e) { if (e.code == 'invalid-credential') { // Email enumeration protection enabled (default since Sep 2023): // replaces 'user-not-found' and 'wrong-password'. print('Invalid email or password.'); } else 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.'); } }
user-not-found and wrong-password with invalid-credential. Manage this in the Firebase console under Authentication > Settings.sendPasswordResetEmail() may complete without an error even if the email is not registered. Treat this as expected behavior and do not use password-reset responses to infer whether an email exists.Google Sign-In (native platforms):
dartFuture<UserCredential> signInWithGoogle() async { final GoogleSignInAccount? googleUser = await GoogleSignIn.instance.authenticate(); final GoogleSignInAuthentication googleAuth = googleUser.authentication; final credential = GoogleAuthProvider.credential(idToken: googleAuth.idToken); return await FirebaseAuth.instance.signInWithCredential(credential); }
Google Sign-In (web):
dartFuture<UserCredential> signInWithGoogle() async { GoogleAuthProvider googleProvider = GoogleAuthProvider(); googleProvider.addScope('https://www.googleapis.com/auth/contacts.readonly'); googleProvider.setCustomParameters({'login_hint': 'user@example.com'}); return await FirebaseAuth.instance.signInWithPopup(googleProvider); }
signInWithProvider opens a Chrome Custom Tab. If AndroidManifest.xml contains android:taskAffinity="" (Flutter's default), the tab closes when the user switches apps (e.g., to use a password manager), causing a web-context-already-presented error. Remove android:taskAffinity="" to fix this.email and name scopes to present the full first-time sign-in UI (including "Share/Hide email"):dart final appleProvider = AppleAuthProvider(); appleProvider.addScope('email'); appleProvider.addScope('name');
revokeTokenWithAuthorizationCode() with the authorization code from userCredential.additionalUserInfo?.authorizationCode.revokeAccessToken() with the access token from userCredential.credential?.accessToken.dart // Apple platforms (iOS/macOS/web) final authCode = userCredential.additionalUserInfo?.authorizationCode; if (authCode != null) { await FirebaseAuth.instance.revokeTokenWithAuthorizationCode(authCode); }
// Android final accessToken = userCredential.credential?.accessToken; if (accessToken != null) { await FirebaseAuth.instance.revokeAccessToken(accessToken); }
Before using phone authentication, ensure platform-specific prerequisites are met:
Phone number sign-in is only supported on real devices and the web. Testing on device emulators is not supported.
iOS: recaptcha-sdk-not-linked error
On iOS, verifyPhoneNumber can throw FirebaseAuthException with code recaptcha-sdk-not-linked when Identity Platform expects reCAPTCHA Enterprise but the native SDK is not linked. This cannot be resolved from Dart — fix it at the native iOS or GCP level:
projects.updateConfig REST API (set recaptchaConfig.phoneEnforcementState to OFF and recaptchaConfig.useSmsTollFraudProtection to false). See the official steps. This reduces fraud protection — prefer linking the SDK.uni_links/app_links or application:openURL: in the iOS runner.try-catch with FirebaseAuthException.e.code to identify specific error types.account-exists-with-different-credential by fetching sign-in methods for the email and guiding users through the correct flow.too-many-requests with retry logic or user feedback.operation-not-allowed by ensuring the provider is enabled in the Firebase console.recaptcha-sdk-not-linked during verifyPhoneNumber is raised by the native Firebase iOS Auth SDK and requires native setup or GCP configuration changes — it cannot be fixed from Dart code alone.dart// Update profile await FirebaseAuth.instance.currentUser?.updateProfile( displayName: "Jane Q. User", photoURL: "https://example.com/jane-q-user/profile.jpg", ); // Update email (sends verification to new address first) await user?.verifyBeforeUpdateEmail("newemail@example.com");
verifyBeforeUpdateEmail() — not updateEmail() — to change a user's email. The email only updates after the user verifies it.linkWithCredential() to connect multiple auth providers to a single account.fetchSignInMethodsForEmail() when handling account linking.FirebaseAuth.instance.signOut() when users exit the app.reauthenticateWithCredential().auth variable to get the signed-in user's UID for access control.> Security warning: Avoid SMS-based MFA. SMS is insecure and easy to compromise or spoof.
> Platform limitation: Windows does not support MFA. MFA with multiple tenants is not supported on Flutter.
> Important: Firebase Dynamic Links is deprecated for email link authentication. Firebase Hosting is now used to send sign-in links.
handleCodeInApp: true in ActionCodeSettings — sign-in must always be completed in the app.SharedPreferences) when sending the sign-in link.Other measured skills in the registry, with their headline benchmark lift.