firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.5k stars 3.92k forks source link

🐛 [firebase_app_check] Can't use Flutter Web with App Check for Authentication enforced (resolvable by editing main.dart.js after building) #11060

Closed cadivus closed 8 months ago

cadivus commented 1 year ago

Bug report

Describe the bug When enforcing App Check for Authentication on Firebase (it's still labeled as beta on Firebase), I can connect my Flutter App compiled for Android and iOS and log in users, but I can't login users in a Flutter web application. If I try logging in user in a Flutter web application with App Check for authentication enforced, I get a 401 error:

https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=***************** 401

If App Check is enforced for Firestore only, it works.

Steps to reproduce

Steps to reproduce the behavior:

  1. Go to Firebase and enforce App Check for Authentication
  2. Run you App for Flutter Web (Firebase App Check needs to be set up).
  3. Log in with email address and password

Expected behavior

I want to be logged in to my app, but I get an App Check error instead.

Sample project

This was my testcode in pure HTML and Javascript for ensuring that it can work for Web Apps:

JS test app (does work) ```javascript ```

This HTML file with some Javascript does work.

This is a part of the Flutter web app:

Flutter web app (does not work with enforced App Check for Authentication) Part of the main.dart ```Dart void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: const FirebaseOptions( apiKey: "apiKey", authDomain: "authDomain", projectId: "projectId", storageBucket: "storageBucket", messagingSenderId: "messagingSenderId", appId: "appId", measurementId: "measurementId", ), ); await FirebaseAppCheck.instance.activate( webRecaptchaSiteKey: "to be replaced", ); ``` The login screen: ```Dart import "package:flutter_app/widgets/forms/login_form.dart"; import "package:firebase_auth/firebase_auth.dart"; import "package:flutter/material.dart"; class LoginScreen extends StatefulWidget { const LoginScreen({Key? key}) : super(key: key); @override State createState() => _LoginScreenState(); } class _LoginScreenState extends State { String error = ""; Future login(email, password) async { try { await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); } on FirebaseAuthException catch (e) { if (e.code == "user-not-found") { // ignore: avoid_print print("No user found for that email."); } else if (e.code == "wrong-password") { // ignore: avoid_print print("Wrong password provided for that user."); } } } void setError(errorMessage) { setState(() { error = errorMessage; }); } @override Widget build(BuildContext context) { return Container( color: const Color(0xFFF5F5F7), child: Center( child: LoginForm( onSubmit: (data) { login(data["email"], data["password"]); }, error: error, ), ), ); } } ``` Part of pubspeck.yaml: ``` firebase_app_check: ^0.1.4+1 ```

This web app does not work.

Additional context

I am able to solve this problem by patching files in build/web.

I noticed that Flutter compiled for web uses firebasejs version 9.18.0, which does not seem to support App Check for Authentication. An indicator for this was that the requests for https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=... looks different in my HTML-Testfile with the newer version:
241604712-25b8f3fa-9c02-489b-bb49-ad47da6a97e0 (clientType was missing in the Firebase App with firebasejs 9.18.0)

Patching main.dart.js for making it work

After replacing the version number in build/web/main.dart.js, the login does work. I did this:

sed -i 's/if(m==null)m="9.18.0"/if(m==null)m="9.22.1"/g' main.dart.js

Because I'm not sure about the variable name m, I changed my CI pipeline to do this instead:

sed -i 's/("https:\/\/www\.gstatic\.com\/firebasejs\/"+this\.[a-zA-Z0-9]*+"\/firebase-/("https:\/\/www\.gstatic\.com\/firebasejs\/9\.22\.1\/firebase-/g' main.dart.js

A downside of this patch

The only problem that I've created by doing this was that I had to login again again after reloading the web app. I was able to resolve that by initializing Firebase in the index.html and use this instance in main.dart.js (initializing it again in main.dart.js makes the app crash).

Another patch for resolving the refresh-problem after the first patch

I was able to make the user stay logged in after patching build/web/index.html and build/web/main.dart.js so that Firebase App and App Check get initialized in the index.html.

Patch for build/web/index.html

index.html_firebasejs_appcheck_patch.txt ``` --- index.html.orig 2023-05-30 10:43:48.190637491 +0200 +++ index.html 2023-05-30 10:32:29.375537469 +0200 @@ -38,8 +38,31 @@ - Githubissues.
  • Githubissues is a development platform for aggregating issues.