Best for
- Setting up Firebase Authentication in a Flutter project.
- Listening to authentication state changes.
- Implementing email/password, phone number, or social sign-in.
evanca/flutter-ai-rules/skills/firebase-auth/SKILL.md
Use when setting up auth, managing auth state, implementing email/password or social sign-in, handling auth errors, or managing users.
Decision brief
This skill defines how to correctly use Firebase Authentication in Flutter applications.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/evanca/flutter-ai-rules --skill "skills/firebase-auth"Inspect the Agent Skill "firebase-auth" from https://github.com/evanca/flutter-ai-rules/blob/b294a77b68b5508f8d3151fb93d87ed9622d2ff1/skills/firebase-auth/SKILL.md at commit b294a77b68b5508f8d3151fb93d87ed9622d2ff1. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Local emulator for testing:
Setting up Firebase Authentication in a Flutter project. Listening to authentication state changes. Implementing email/password, phone number, or social sign-in. Managing user profiles, account linking, or MFA. Handling authentication errors (including iOS recaptcha-sdk-not-link…
Use the appropriate stream based on what you need to observe:
Verify the user's email address after account creation.
Google Sign-In (native platforms):
Permission review
The documentation includes network, browsing, or remote request actions.
googleProvider.addScope('https://www.googleapis.com/auth/contacts.readonly');The documentation includes network, browsing, or remote request actions.
photoURL: "https://example.com/jane-q-user/profile.jpg",Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 89/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 604 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
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_auth
import 'package:firebase_auth/firebase_auth.dart';
Local emulator for testing:
Future<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) |
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
Create a new account:
try {
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:
try {
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):
Future<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):
Future<UserCredential> signInWithGoogle() async {
GoogleAuthProvider googleProvider = GoogleAuthProvider();
googleProvider.addScope('https://www.googleapis.com/auth/contacts.readonly');
googleProvider.setCustomParameters({'login_hint': '[email protected]'});
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"):
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.// 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.// 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("[email protected]");
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.