Flutter Google sign in for web

eye-catch Dart and Flutter

The way to sign in from web version is a bit different from Android. I write down some problems that I faced. I hope this article can help some developers.

Sponsored links

Conclusion

Conclusion first.

  • Not necessary to change index.html
  • Specify client ID to GoogleSignIn when initializing it
  • Specify FirebaseOptions into initializeApp
  • Set the URI with correct port in Google Cloud Platform
Sponsored links

FirebaseOptions cannot be null when creating the default app

I’ve already tried to sign in to Google from an android application. The steps for it is described here.

So I took the code from there. Initialize app first.

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  runApp(const HomeView());
}

Once Firebase project is created for a web app, the page tells us that we need to add the script below to index.html.

<!DOCTYPE html>
<html>
<head>
 ...
</head>
<body>
  ...

  <!-- add the script from here -->
  <script type="module">
    // Import the functions you need from the SDKs you need
    import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.1/firebase-app.js";
    // TODO: Add SDKs for Firebase products that you want to use
    // https://firebase.google.com/docs/web/setup#available-libraries

    // Your web app's Firebase configuration
    const firebaseConfig = {
        apiKey: "my-value",
        authDomain: "my-value",
        projectId: "my-value",
        storageBucket: "my-value",
        messagingSenderId: "my-value",
        appId: "my-value"
    };

    // Initialize Firebase
    const app = initializeApp(firebaseConfig);
  </script>
</body>
</html>

But the following error occurred when the app starts.

Restarted application in 6,434ms.
Error: Assertion failed:
..\…\src\firebase_core_web.dart:273
options != null
"FirebaseOptions cannot be null when creating the default app."
    at Object.throw_ [as throw] (http://localhost:61206/dart_sdk.js:5063:11)
    at Object.assertFailed (http://localhost:61206/dart_sdk.js:4988:15)
at firebase_core_web.FirebaseCoreWeb.new.initializeApp (http://localhost:61206/packages/firebase_core_web/firebase_core_web.dart.lib.js:252:42)
    at initializeApp.next (<anonymous>)
    at http://localhost:61206/dart_sdk.js:40192:33
    at _RootZone.runUnary (http://localhost:61206/dart_sdk.js:40062:59)
    at _FutureListener.thenAwait.handleValue (http://localhost:61206/dart_sdk.js:34983:29)
    at handleValueCallback (http://localhost:61206/dart_sdk.js:35551:49)
    at Function._propagateToListeners (http://localhost:61206/dart_sdk.js:35589:17)
    at _Future.new.[_completeWithValue] (http://localhost:61206/dart_sdk.js:35437:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:61206/dart_sdk.js:35458:35)
    at Object._microtaskLoop (http://localhost:61206/dart_sdk.js:40330:13)
    at _startMicrotaskLoop (http://localhost:61206/dart_sdk.js:40336:13)
    at http://localhost:61206/dart_sdk.js:35811:9

ClientID not set. Either set it on a <meta name=\"google-signin-client_id\" content=\"CLIENT_ID\" /> tag

The options have to be set in initializeApp function and it is not necessary to call it in index.html because it’s already called in main function. I moved them from index.html.

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: const FirebaseOptions(
        apiKey: "my-value",
        authDomain: "my-value",
        projectId: "my-value",
        storageBucket: "my-value",
        messagingSenderId: "my-value",
        appId: "my-value"),
  );

  runApp(const HomeView());
}

An error occurred again when it tried to sign in.

Restarted application in 8,662ms.
Error: Assertion failed:
..\…\lib\google_sign_in_web.dart:77
appClientId != null
"ClientID not set. Either set it on a <meta name=\"google-signin-client_id\" content=\"CLIENT_ID\" /> tag, or pass clientId when calling init()"
    at Object.throw_ [as throw] (http://localhost:61206/dart_sdk.js:5063:11)
    at Object.assertFailed (http://localhost:61206/dart_sdk.js:4988:15)
at google_sign_in_web.GoogleSignInPlugin.new.init (http://localhost:61206/packages/google_sign_in_web/google_sign_in_web.dart.lib.js:107:42)
...

I added the following meta tag at first.

<meta name="google-signin-client_id" content="my-client-id-xxxxxxxxxxxxxxxxx.apps.googleusercontent.com">

But it was not necessary again. It needs to be set here.

final googleSignIn = GoogleSignIn(
  clientId: "my-client-id-xxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
  scopes: [
  sc.SearchConsoleApi.webmastersReadonlyScope,
]);

Not a valid origin for the client

Even if I set the client ID, an error occurred again!

Error: PlatformException(idpiframe_initialization_failed, Not a valid origin for the client: http://localhost:61206 has not been registered for client ID my-client-id-xxxxxxxxxxxxxxxxx.apps.googleusercontent.com. Please go to https://console.developers.google.com/ and register this origin for your project's client ID., https://developers.google.com/identity/sign-in/web/reference#error_codes, null)
    at Object.createErrorWithStack (http://localhost:61206/dart_sdk.js:5076:12)
    at Object._rethrow (http://localhost:61206/dart_sdk.js:40477:16)
    at async._AsyncCallbackEntry.new.callback (http://localhost:61206/dart_sdk.js:40473:13)
    at Object._microtaskLoop (http://localhost:61206/dart_sdk.js:40330:13)
    at _startMicrotaskLoop (http://localhost:61206/dart_sdk.js:40336:13)
    at http://localhost:61206/dart_sdk.js:35811:9

This is because the used port is not specified on the credentials page. Only default port 80 and 5000 are available.

Specify port number for Flutter web

The port is not fixed by default. To fix the port number, we need to do run a command or configure it in launch.json.

Command line

If I ran the app with the following command, it worked as expected.

flutter run -d chrome --web-hostname localhost --web-port 5000

But it seems that we need to do additional work if we want to debug the code.

launch.json

I don’t want to run the command every time I want to start the app. It’s easier if it starts by pressing F5. Let’s configure it in launch.json file.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "app_name",
            "request": "launch",
            "type": "dart",
            "args": [
                "-d",
                "chrome",
                "--web-hostname",
                "localhost",
                "--web-port",
                "5000"
            ]
        },
    ]
}

With this configuration, we can start the app easily.

CONFIGURATION_NOT_FOUND error

[firebase_auth/internal-error] {"error":{"code":400,"message":"CONFIGURATION_NOT_FOUND","errors":[{"message":"CONFIGURATION_NOT_FOUND","domain":"global","reason":"invalid"}]}}

If you got this message above, you need to enable Google as you can see in the image below.

You might also want to check

A user needs to do the login process again if the app is closed and opened again. This post explains how to keep the login state.

Comments

  1. Juan de Villeros says:

    Excellent article, you set me on the proper track. Thanks!

  2. Manoj says:

    Thanks for helping out. It is a great article.
    I am needing support for different Google Client Id based on if it is DEV or PROD environment. I just did not know how to do that in index.html.

Copied title and URL