google_apple_sign_in 1.0.1
google_apple_sign_in: ^1.0.1 copied to clipboard
Sign in with Google and Apple behind one interface. Returns the id token and nonce your backend or Firebase needs, and follows App Store guideline 4.8.
google_apple_sign_in #
Sign in with Google and Apple in Flutter behind one interface. You get back the id token (and, for Apple, the raw nonce) that Firebase or your own backend needs, and the buttons follow App Store guideline 4.8 for you.
final signIn = PlatformSocialSignIn(const SocialSignInConfig(
googleClientId: 'IOS_CLIENT_ID.apps.googleusercontent.com',
googleServerClientId: 'WEB_CLIENT_ID.apps.googleusercontent.com',
appleSignIn: true,
));
for (final p in signIn.providers) { /* show a button per provider */ }
final credential = await signIn.signIn(SocialProvider.apple);
// credential.idToken, credential.rawNonce, credential.email, credential.displayName
It wraps google_sign_in 7 and sign_in_with_apple 8. It does not talk to any backend and does not depend on Firebase.
Why #
Getting both providers working on both platforms is mostly configuration, and the failures are quiet:
- Google on Android returns no id token unless you pass the Web client id as
serverClientId. You getSocialSignInFailure: Google returned no id token. Set googleServerClientId.instead of a null you find later. - Google on Android fails in release only when the SHA-1 of the Play app-signing key is not registered. You need one Android OAuth client per signing key (debug, upload, Play).
- App Store guideline 4.8: an iOS app that offers a third-party login such as Google must also offer an equivalent privacy-focused login (data limited to name and email, email can be hidden, no tracking). Sign in with Apple is the standard way to meet it, so
providershides the Google button on iOS until Apple is configured, and a debug build tells you why. - Apple + Firebase needs a nonce: the SHA-256 goes to Apple, the raw value goes to Firebase. The package generates both and returns
rawNonce. - Apple on Android works through a web flow with a Services ID and a server callback. The button is offered on Android only when
appleServiceIdis set. - Cancel is not an error: both SDKs' cancel codes become
SocialSignInCancelled; everything else becomesSocialSignInFailurewith the provider attached.
Install #
flutter pub add google_apple_sign_in
Supported: Android and iOS. Apple sign-in on the web works through sign_in_with_apple; Google on the web needs the button that google_sign_in renders, so signIn(SocialProvider.google) throws a SocialSignInFailure there.
The API #
SocialSignIn |
The interface: providers, signIn(provider), signOut(). Depend on this in your app. |
PlatformSocialSignIn(config) |
The real implementation. |
FakeSocialSignIn |
For tests and demo builds. Returns a made-up credential; cancel: true simulates the user backing out. |
SocialSignInConfig |
Client ids and switches. Empty string = not set up. |
SocialCredential |
provider, idToken, email, displayName; Apple adds authorizationCode and rawNonce. |
SocialSignInCancelled / SocialSignInFailure |
The only two exceptions you need to catch. |
try {
final c = await signIn.signIn(SocialProvider.google);
await backend.exchange(c.idToken);
} on SocialSignInCancelled {
// user closed the sheet: do nothing
} on SocialSignInFailure catch (e) {
showError('${e.provider?.name}: ${e.message}');
}
Setup: the four configurations #
You need a Google Cloud project (free) and, for Apple, a paid Apple Developer account.
1. Google on Android #
-
Google Cloud console → APIs & Services → Credentials. Configure the OAuth consent screen first if asked.
-
Create a Web application OAuth client. Its client id is
googleServerClientId. Android needs it to return an id token. -
Create an Android OAuth client for each signing key, with your package name and that key's SHA-1:
- debug:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android - upload key: the same command against your upload keystore, or
cd android && ./gradlew signingReport - Play app signing: Play Console → your app → App integrity → App signing → "App signing key certificate".
Miss the last one and sign-in works in your builds but fails for everyone who installs from Play.
- debug:
-
No
google-services.jsonis needed for this package.
2. Google on iOS #
- Create an iOS OAuth client with your bundle id. Its client id is
googleClientId. - Add its reversed client id as a URL scheme in
ios/Runner/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.YOUR_IOS_CLIENT_ID</string>
</array>
</dict>
</array>
- Also set
googleServerClientId(the Web client from step 1.2) if your backend verifies the token, so the token's audience is the same on both platforms. - Remember 4.8: the Google button appears on iOS only once Apple is set up as well.
3. Apple on iOS #
- Apple Developer → Certificates, Identifiers & Profiles → Identifiers → your App ID → enable Sign in with Apple.
- Xcode → Runner target → Signing & Capabilities → + Capability → Sign in with Apple.
- Set
appleSignIn: true. Leave it false until both steps are done: a button on an App ID without the capability fails on every tap.
Apple sends the user's name and email only on the first sign-in for that Apple ID. Save them then; later sign-ins return displayName == null.
4. Apple on Android #
Android has no native Apple sign-in, so sign_in_with_apple opens a web flow:
- Apple Developer → Identifiers → Services IDs → create one (for example
com.example.app.signin). This isappleServiceId. - Configure it for Sign in with Apple: primary App ID, your domain, and a Return URL on your server (for example
https://api.example.com/auth/apple/callback). This isappleRedirectUri. - That endpoint receives Apple's form POST and must redirect back into the app:
intent://callback?<the posted fields as a query string>#Intent;package=YOUR.PACKAGE.NAME;scheme=signinwithapple;end - Add the callback activity to
android/app/src/main/AndroidManifest.xml, inside<application>:
<activity
android:name="com.aboutyou.dart_packages.sign_in_with_apple.SignInWithAppleCallback"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="signinwithapple" android:path="/callback" />
</intent-filter>
</activity>
- Set
appleSignIn: trueandappleServiceId/appleRedirectUri.
Using the credential #
With Firebase Auth #
final c = await signIn.signIn(provider);
final AuthCredential cred = switch (c.provider) {
SocialProvider.google => GoogleAuthProvider.credential(idToken: c.idToken),
SocialProvider.apple => OAuthProvider('apple.com').credential(
idToken: c.idToken,
rawNonce: c.rawNonce,
accessToken: c.authorizationCode,
),
};
await FirebaseAuth.instance.signInWithCredential(cred);
Enable Google and Apple under Firebase console → Authentication → Sign-in method. For Apple, rawNonce is required.
With your own backend #
Send idToken (and for Apple rawNonce) and verify the JWT on the server. Do not trust email / displayName from the client.
- Signature: Google's keys at
https://www.googleapis.com/oauth2/v3/certs, Apple's athttps://appleid.apple.com/auth/keys. iss:https://accounts.google.com(oraccounts.google.com) /https://appleid.apple.com.aud: your Web client id for Google; your bundle id (iOS) or Services ID (Android) for Apple.expin the future; for Apple, thenonceclaim equals SHA-256 ofrawNonce.- Key users on
sub, not email. Apple may give a private relay address.
Testing #
Depend on SocialSignIn, not on PlatformSocialSignIn, and pass FakeSocialSignIn in tests:
final fake = FakeSocialSignIn();
await myLoginController(fake).tapGoogle();
expect(fake.calls, 1);
fake.cancel = true; // the next signIn throws SocialSignInCancelled
SocialSignInConfig.offered(applePlatform: true) lets you test which buttons iOS would show without a device.
FAQ #
Do I need Firebase? No. The package returns tokens; Firebase is one way to use them.
Why is the Google button missing on my iPhone? App Store guideline 4.8 asks for an equivalent privacy-focused login next to Google, and this package uses Sign in with Apple for that. Configure it and set appleSignIn: true; a debug build prints this in the console.
Google works in debug but not from the Play Store. Register the SHA-1 of the Play app-signing key as another Android OAuth client (setup step 1.3).
Google returns no id token on Android. Set googleServerClientId to the Web client id, not the Android one.
Apple returns no name on the second sign-in. That is Apple's behavior. Store the name the first time. To test the first-time flow again, remove the app under Settings → Apple ID → Sign-In & Security → Sign in with Apple.
About #
Extracted from the coderqh Flutter app templates, where it backs the Google and Apple buttons in every app. Issues and pull requests are welcome.
MIT licensed.