Search code examples
flutterdartgoogle-cloud-platformgoogle-oauthserverpod

Serverpod's Google Sign In is giving me - Failed call: serverpod_auth.google.authenticateWithServerAuthCode


I am trying to implement Google Sign in using Serverpod and Flutter and its not working..

Error Logs right after the App is started on Android Emulator -

Syncing files to device sdk gphone x86...
D/ProfileInstaller(20285): Installing profile for com.kaaljit.talkinbird
I/flutter (20285): Failed call: serverpod_auth.status.getUserInfo
I/flutter (20285): SocketException: HTTP connection timed out after 0:00:20.000000, host: <My IP Address>, port: 8080
I/flutter (20285): Failed call: user.getUser
I/flutter (20285): SocketException: HTTP connection timed out after 0:00:20.000000, host: <My IP Address>, port: 8080
[log] SocketException: HTTP connection timed out after 0:00:20.000000, host: <My IP Address>, port: 8080
I/flutter (20285): serverpod_auth_google: GoogleSignIn
I/flutter (20285): serverpod_auth_google: Signing out from google
I/flutter (20285): serverpod_auth_google: PlatformException(status, Failed to disconnect., null, null)
I/flutter (20285): Failed call: serverpod_auth.google.authenticateWithServerAuthCode
I/flutter (20285): SocketException: HTTP connection timed out after 0:00:20.000000, host: <My IP Address>, port: 8080
I/flutter (20285): serverpod_auth_google: SocketException: HTTP connection timed out after 0:00:20.000000, host: <My IP Address>, port: 8080
I/flutter (20285): #0      _ConnectionTarget.connect.<anonymous closure>.<anonymous closure> (dart:_http/http_impl.dart:2530:11)
I/flutter (20285): #1      _FutureListener.handleError (dart:async/future_impl.dart:180:22)
I/flutter (20285): #2      Future._propagateToListeners.handleError (dart:async/future_impl.dart:850:47)
I/flutter (20285): #3      Future._propagateToListeners (dart:async/future_impl.dart:871:13)
I/flutter (20285): #4      Future._completeError (dart:async/future_impl.dart:651:5)
I/flutter (20285): #5      Future.timeout.<anonymous closure> (dart:async/future_impl.dart:923:17)
I/flutter (20285): #6      Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
I/flutter (20285): #7      _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
I/flutter (20285): #8      _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
I/flutter (20285): #9      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

main.dart -

late SessionManager sessionManager;
late Client client;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  const ipAddress = <My IP Address>;
  // const ipAddress = '10.0.0.2';

  client = Client(
    'http://$ipAddress:8080/',
    authenticationKeyManager: FlutterAuthenticationKeyManager(),
  )..connectivityMonitor = FlutterConnectivityMonitor();

  sessionManager = SessionManager(
    caller: client.modules.auth,
  );
  await sessionManager.initialize();

  runApp(const TalkinBird());
}

Sign In Screen -

import 'package:flutter/material.dart';
import 'package:serverpod_auth_google_flutter/serverpod_auth_google_flutter.dart';
import 'package:talkinbird_flutter/screens/user_details_ui.dart';

import '../main.dart';

const _serverClientId = "<Web Application's Client ID>";

class SignInPage extends StatelessWidget {
  const SignInPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Dialog(
          child: Container(
            width: 260,
            padding: const EdgeInsets.all(16),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                SignInWithGoogleButton(
                  onSignedIn: () {
                    print('Signed in with Google!');
                    Navigator.of(context).push(MaterialPageRoute(
                      builder: (context) => const UserDetailsUI(),
                    ));
                  },
                  caller: client.modules.auth,
                  serverClientId: _clientId,
                  redirectUri: Uri.parse('http://localhost:8082/googlesignin'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Serverpod versions

  • CLI Version: 1.2.6
  • Library version: 1.2.6

Platform information I am on a Windows Machine, using Android Studio and working on Pixel 8 API 30 Android Emulator. I have defined org.gradle.jvmargs=-XX:MaxHeapSize=256m -Xmx2536m in gradle.properties and multidex support is enabled. In my app/gradle - compileSdk is 34, ndkVersion "25.1.8937393", minSdkVersion is flutter.minSdkVersion, targetSdkVersion is flutter.targetSdkVersion

Here is the flutter doctor's outopt -

PS C:\talkinbird\talkinbird_flutter> flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.19.4, on Microsoft Windows [Version 10.0.22621.3296], locale en-IN)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.7.6)
[√] Android Studio (version 2023.2)
[√] Connected device (4 available)
[√] Network resources

• No issues found!

What I am doing

  1. I have added serverpod_auth_server: 1.2.6 in server's pubspec, pod.webServer.addRoute(auth.RouteGoogleSignIn(), '/googlesignin'); in server.dart and ran serverpod generate, applied migrations and ran the web server.
  2. I have defined modules: serverpod_auth: nickname: auth in generator.yaml
  3. I have added serverpod_auth_client: 1.2.6 in Client's pubspec
  4. I have added serverpod_auth_shared_flutter: 1.2.6 and serverpod_auth_google_flutter: 1.2.6 in Flutter App's pubspec.
  5. I have created a project in GCP and enabled People API
  6. I have created Client ID for Web Application - Defined Authorized JavaScript origins as http://localhost:8082 and http://localhost:49660. Defined Authorized redirect URIs as http://localhost:8082, http://localhost:49660, http://localhost:8082/googlesignin.
  7. I have downloaded the Web Application JSON and stored it as server/config/google_client_secret.json.
  8. I have created Client ID for Android and defined SHA-1 certificate fingerprint. I have downloaded the Json file and stored it as talkinbird_flutter/android/app/google-services.json.
  9. I am testing on emulator so my PC and my AVD both has the same IP.
  10. I have tried using my own IP Address and 10.0.0.2 - Using my own IP Address takes me to OAuth Consent Screen and then give me error, Using 10.0.0.2 straight away gives me error after clicking on my gmail id.
  11. I have tried using both Android's Client ID and Web Application's Client ID in SignInWithGoogleButton and found out that the Web Application one takes me to OAuth Consent Screen so I belive its the right one to use.
  12. I have tried running './gradlew clean', flutter clean and flutter pub cache repair and Invalidate Cache and Restart in Android Studio multiple times in between trying various solutions as mentioned above.

Expected behavior onSignedIn callback gets executed and Navigator takes me to the next screen as defined.


Solution

  • I'm not quite sure if this is the similar error that I was facing since I'm using latest (2.0.1) serverpod and all serverpod related packages at the time of writing. They handled errors more gracefully and now error logs are a bit different.

    I also had some misleading logs. It turned out that if you've followed serverpod's guide for google auth, they skipped an important part of setup.

    And that is configuring redirect uris. According to this issue, google_client_secret.json could not be read if redirect_uris key is missing from the json file.

    The fix for me was to go to the google cloud console, edit credentials for your Serverpod server, and add Authorized redirect URIs to match the one I'm using in my call. Then I just downloaded json file again, renamed to google_client_secret.json and all of a sudden, everything worked. Just check if your google_client_secret.json contains something like:

    {
        "web": {
           ...
            "redirect_uris": [
                "http://localhost:8082/googlesignin"
            ]
        }
    }