WE ARE HIRING • WE ARE HIRING • 
200 Happy Clients Worldwide
Delivering Excellence Since 2019
AI Workflow Automation with n8n & LangChain
WhatsApp Business Automation & AI Chatbots
24/7 Voice AI Agents Always On, Never Missed
Intelligent AI CRM & Lead Management Systems
Real-Time Business Dashboards & Analytics
AI Customer Support Resolve Tickets Instantly
Custom Internal Tools Built for Your Team
Powered by OpenAI, LangChain & Cutting-Edge AI
400+ App Integrations via Zapier & n8n
Helping Businesses Across Industries
End-to-End Automation Zero Manual Handoffs
200 Happy Clients Worldwide
Delivering Excellence Since 2019
AI Workflow Automation with n8n & LangChain
WhatsApp Business Automation & AI Chatbots
24/7 Voice AI Agents Always On, Never Missed
Intelligent AI CRM & Lead Management Systems
Real-Time Business Dashboards & Analytics
AI Customer Support Resolve Tickets Instantly
Custom Internal Tools Built for Your Team
Powered by OpenAI, LangChain & Cutting-Edge AI
400+ App Integrations via Zapier & n8n
Helping Businesses Across Industries
End-to-End Automation Zero Manual Handoffs
200 Happy Clients Worldwide
Delivering Excellence Since 2019
AI Workflow Automation with n8n & LangChain
WhatsApp Business Automation & AI Chatbots
24/7 Voice AI Agents Always On, Never Missed
Intelligent AI CRM & Lead Management Systems
Real-Time Business Dashboards & Analytics
AI Customer Support Resolve Tickets Instantly
Custom Internal Tools Built for Your Team
Powered by OpenAI, LangChain & Cutting-Edge AI
400+ App Integrations via Zapier & n8n
Helping Businesses Across Industries
End-to-End Automation Zero Manual Handoffs
flutterApril 6, 2026

Google & Apple Sign-In in Flutter

Introduction A production-grade walkthrough clean auth service, real code from a real app, and integration patterns. Every additional step between a user opening your app and being inside it is a drop-off point. Google a

Mind Stack Labs

Engineering Team

Google & Apple Sign-In in Flutter

Introduction

A production-grade walkthrough clean auth service, real code from a real app, and integration patterns. Every additional step between a user opening your app and being inside it is a drop-off point. Google and Apple Sign-In are the fastest path from “curious” to “engaged” two taps and you’re in, no password to forget.

01 / Prerequisites

  • A Firebase project with Authentication enabled Google and Apple providers turned on.
  • FlutterFire CLI installed and flutterfire configure already run.
  • For Apple Sign-In: an Apple Developer account with Sign In with Apple capability enabled.
  • For Android Google Sign-In: SHA-1 fingerprint registered in Firebase Console.

02 / Dependencies & Setup

Add to pubspec.yaml

dependencies:
  flutter_dotenv: ^5.2.1
  firebase_core: ^3.10.1
  firebase_auth: ^5.5.1
  google_sign_in: ^7.2.0
  sign_in_with_apple: ^7.0.1

flutter:
  assets:
    - .env

Then run:

flutter pub get

Create your .env file

Store sensitive config outside of source code. Create a .env file in your project root and add it to .gitignore:

SERVER_CLIENT_ID=123456789-abcdefg.apps.googleusercontent.com

Initialize Firebase in main.dart

You must call GoogleSignIn.instance.initialize() before runApp(), after Firebase is ready:

import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:your_app/service/auth_service.dart';

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

  await dotenv.load(fileName: '.env');

  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  await AuthService().initialize();

  runApp(const MyApp());
}

⚠️ If you call authenticate() or authorizationClient before initialize(), Flutter throws a StateError: instance not initialized. This crashes silently in release builds. Always initialize first.

03 / Getting the Server Client ID

The serverClientId is the Web Client ID from Google Cloud Console not the Android or iOS client. It is required for Google Sign-In on Android and enables server-side token verification.

  1. Go to console.cloud.google.com and select your Firebase project.
  2. Navigate to APIs & Services → Credentials.
  3. Under OAuth 2.0 Client IDs, find the entry with type “Web application” usually named “Web client (auto created by Google Service)”.
  4. Click it and copy the Client ID field it ends in .apps.googleusercontent.com.
  5. Paste it into your .env file as SERVER_CLIENT_ID=.

Can’t find the Web Client? Go to Firebase Console → Authentication → Sign-in method → Google → expand arrow. Firebase will show the Web SDK configuration containing the same client ID.

04 / The Clean AuthService

Here’s the full authentication service auth logic only, no database concerns. Use it as a foundation and add your own data layer on top.

lib/service/auth_service.dart

import 'dart:developer' as log;
import 'dart:math';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';

class AuthService {
  static final AuthService _instance = AuthService._internal();
  factory AuthService() => _instance;
  AuthService._internal();

  final FirebaseAuth _auth = FirebaseAuth.instance;
  final GoogleSignIn _googleSignIn = GoogleSignIn.instance;

  String get _serverClientId => dotenv.env['SERVER_CLIENT_ID'] ?? '';

  User? get currentUser => _auth.currentUser;
  bool get isSignedIn => currentUser != null;

  Future initialize() async {
    try {
      await _googleSignIn.initialize(serverClientId: _serverClientId);
      log.log('[AuthService] Google Sign-In initialized');
    } catch (e) {
      log.log('[AuthService] Google init error: $e');
      rethrow;
    }
  }

  Future signInWithGoogle() async {
    await _googleSignIn.signOut();
    final GoogleSignInAccount googleUser =
        await _googleSignIn.authenticate(scopeHint: ['email']);
    final GoogleSignInAuthentication googleAuth = googleUser.authentication;
    final authClient = _googleSignIn.authorizationClient;
    final authorization =
        await authClient.authorizationForScopes(['email', 'profile']);
    final credential = GoogleAuthProvider.credential(
      idToken: googleAuth.idToken,
      accessToken: authorization?.accessToken,
    );
    return _auth.signInWithCredential(credential);
  }

  Future signInWithApple() async {
    final rawNonce = _generateNonce();
    final appleCredential = await SignInWithApple.getAppleIDCredential(
      scopes: [
        AppleIDAuthorizationScopes.email,
        AppleIDAuthorizationScopes.fullName,
      ],
    );
    final oAuthCredential = OAuthProvider('apple.com').credential(
      idToken: appleCredential.identityToken,
      rawNonce: rawNonce,
      accessToken: appleCredential.authorizationCode,
    );
    return _auth.signInWithCredential(oAuthCredential);
  }

  Future signOut() async {
    await Future.wait([
      _auth.signOut(),
      _googleSignIn.signOut(),
    ]);
  }

  static String getFirebaseErrorMessage(FirebaseAuthException e) {
    switch (e.code) {
      case 'user-not-found': return 'No account found with this email.';
      case 'wrong-password': return 'Incorrect password.';
      case 'email-already-in-use': return 'This email is already registered.';
      case 'invalid-email': return 'Please enter a valid email.';
      case 'weak-password': return 'Password is too weak.';
      case 'too-many-requests': return 'Too many attempts. Try again later.';
      case 'network-request-failed': return 'No internet connection.';
      case 'operation-not-allowed': return 'This sign-in method is not enabled.';
      case 'account-exists-with-different-credential':
        return 'An account with this email exists with a different sign-in method.';
      default: return 'Authentication failed. Please try again.';
    }
  }

  String _generateNonce([int length = 32]) {
    const charset =
        '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
    final random = Random.secure();
    return List.generate(
        length, (_) => charset[random.nextInt(charset.length)]).join();
  }
}

05 / Platform Configuration

Android Get SHA-1 Fingerprint

keytool -list -v \
  -keystore ~/.android/debug.keystore \
  -alias androiddebugkey \
  -storepass android -keypass android

Add this SHA-1 in Firebase Console → Project Settings → Your Android app → Add fingerprint. Then re-download google-services.json and place it at android/app/google-services.json.

⚠️ Add both debug and release SHA-1. Missing the release SHA-1 causes silent failures after publishing to the Play Store.

Android Verify build.gradle files

android/build.gradle

buildscript {
  dependencies {
    classpath 'com.google.gms:google-services:4.4.2'
  }
}

android/app/build.gradle

apply plugin: 'com.google.gms.google-services'

iOS Add Reversed Client ID URL Scheme

Open GoogleService-Info.plist, find the REVERSED_CLIENT_ID value, then add it to ios/Runner/Info.plist:

CFBundleURLTypes

  
    CFBundleTypeRole
    Editor
    CFBundleURLSchemes
    
      com.googleusercontent.apps.YOUR_REVERSED_CLIENT_ID
    
  

iOS Apple Sign-In Setup

  1. Open ios/Runner.xcworkspace in Xcode → Runner target → Signing & Capabilities → + Capability → Sign In with Apple.
  2. Log into developer.apple.com → Identifiers → select your App ID → check Sign In with Apple → Save. Regenerate your provisioning profile.
  3. Firebase Console → Authentication → Sign-in method → Apple → Enable. Paste your App ID as the Service ID.
  4. Xcode handles the entitlement automatically. Verify Runner.entitlements contains com.apple.developer.applesignin with value Default.

06 / Common Errors & Fixes

  • StateError: instance not initialized — Call await AuthService().initialize() in main() before runApp().
  • sign_in_failed (Android) — SHA-1 missing or incorrect. Add both debug and release SHA-1 in Firebase Console, then re-download google-services.json.
  • PlatformException: sign_in_canceled — User closed the picker. Expected behavior — handle silently without showing an error toast.
  • operation-not-allowed — Go to Firebase Console → Authentication → Sign-in method → Enable Google.
  • idToken is null — Always check googleAuth.idToken != null before creating credentials.
  • Missing REVERSED_CLIENT_ID (iOS) — Add CFBundleURLSchemes using the REVERSED_CLIENT_ID from GoogleService-Info.plist.
  • AuthorizationError: canceled (Apple) — Catch SignInWithAppleAuthorizationException and ignore when e.code == AuthorizationErrorCode.canceled.
  • Apple name is null (returning user) — Apple only provides the name on first sign-in. Save it to your database when isNewUser == true.
  • account-exists-with-different-credential — Use fetchSignInMethodsForEmail() and guide the user to link accounts.
  • Apple Sign-In not working on Simulator — iOS Simulator does not support Apple Sign-In. Always test on a real device.

07 / UI Example

Future loginWithGoogle() async {
  setState(() => isLoading = true);
  final result = await AuthService().signInWithGoogle();
  setState(() => isLoading = false);
  if (result.isSuccess) {
    _showMessage("Google Login Success ✅");
  } else {
    _showMessage(result.error ?? "Error");
  }
}

Future loginWithApple() async {
  setState(() => isLoading = true);
  final result = await AuthService().signInWithApple();
  setState(() => isLoading = false);
  if (result.isSuccess) {
    _showMessage("Apple Login Success 🍎");
  } else {
    _showMessage(result.error ?? "Error");
  }
}

08 / Conclusion & Best Practices

  • Initialize once — call AuthService().initialize() in main() after Firebase and before runApp().
  • Server Client ID = Web Client — get the Web application client from Google Cloud Console, not Android or iOS.
  • Sign out Google on each sign-in — call _googleSignIn.signOut() before authenticating so the picker always appears.
  • Both tokens for Firebase — always pass both idToken and accessToken to GoogleAuthProvider.credential().
  • Use a secure nonce for Apple — generate with Random.secure(), always pass rawNonce to the Firebase credential.
  • Save Apple name immediately — it’s only available on the first sign-in; save to your database when isNewUser == true.
  • Detect new vs returning users — use userCredential.additionalUserInfo?.isNewUser to branch your post-auth flow.
  • Sign out from both — always call both _auth.signOut() and _googleSignIn.signOut() on logout.
  • SHA-1: debug + release — add both fingerprints to Firebase or Google Sign-In breaks in production builds.
  • Test Apple on a real device — iOS Simulator does not support Apple Sign-In.
Keep Reading
Related Articles

You Might Also Like

HeyGen vs Tavus vs Anam: Which AI Avatar Platform Is Right for You in 2026?
flutterMay 21, 2026

HeyGen vs Tavus vs Anam: Which AI Avatar Platform Is Right for You in 2026?

The Real Difference Nobody Explains Properly The AI avatar industry is exploding right now but most people compare HeyGen, Tavus, and Anam as if they are the same type of product. They are NOT. This confusion causes many startups and mobile app builders to choose the wrong platform. HeyGen : mainly an AI video generation […]

Read more
FlutterFlow’s New Feature: App Events (A Game Changer for Scalable Apps)
flutterApr 21, 2026

FlutterFlow’s New Feature: App Events (A Game Changer for Scalable Apps)

Introduction Building scalable applications in low-code platforms has always been a balance between speed and maintainability. While FlutterFlow makes UI development incredibly fast, managing communication between different parts of an app could sometimes become complex. With the introduction of App Events, FlutterFlow has taken a major step forward bringing cleaner architecture, better performance, and a […]

Read more
Integrating Tamara Payment Gateway in a FlutterFlow Application
flutterApr 21, 2026

Integrating Tamara Payment Gateway in a FlutterFlow Application

Introduction Integrating a reliable payment gateway is essential for delivering a smooth and secure user experience. Building a payment system isn’t just about processing transactions it’s about ensuring security, reliability, and compliance, all while maintaining a seamless user journey. Here’s how I integrated the Tamara Payment Gateway into a FlutterFlow application, creating a complete end-to-end […]

Read more
How I Built a Production-Ready AI Chat App in FlutterFlow (With OpenAI + Firebase)
flutterApr 20, 2026

How I Built a Production-Ready AI Chat App in FlutterFlow (With OpenAI + Firebase)

Introduction AI is everywhere in 2026 but building a production-ready AI chat app is still challenging, especially when using low-code tools like FlutterFlow. In this article, I’ll walk you through how I built a scalable AI chat system using FlutterFlow + Firebase + OpenAI API. Architecture Overview Frontend : FlutterFlow UI Backend : Firebase (Firestore […]

Read more