Flutter + Firebase: Sign in with Apple

Karel Debedts
3 min readDec 18, 2019

--

Firebase Auth 0.15.3 brings support for ‘Sign In with Apple’.

“Sign in with Apple makes it easy for users to sign in to your apps and websites using their Apple ID. Instead of filling out forms, verifying email addresses, and choosing new passwords, they can use Sign in with Apple to set up an account and start using your app right away. All accounts are protected with two-factor authentication for superior security, and Apple will not track users’ activity in your app or website.” Source: Apple.com

Before starting, you will need to enable sign in with apple from the developer console. You also need to open the ios folder (from the flutter app) in xcode and add sign in with apple there (capibilities).

https://help.apple.com/developer-account/#/devde676e696

Remember that Sign in with Apple is only supported on IOS 13 and xcode 11.

Let’s get started.

Install these dependencies:

apple_sign_in: ^0.1.0
firebase_auth: ^0.15.3
device_info
: ^0.4.1+4

We need to know if the device supports Sign in with Apple, because ios 12 won’t support it. You can use this in your init state. In this example, a bool is set to true.

bool supportsAppleSignIn = false;
// this bool will be true if apple sign in is enabled
if (Platform.isIOS) {
supportsAppleSignIn = await AppleSignIn.isAvailable();
}

Okay, now we need a button that the user can tap to sign in with apple. But Apple has design guidelines, so we need to use a specific button included in the package ‘apple_sign_in’.

(I put the button in a container to make it smaller)

Container(
height: screenHeight / 15,
width: screenWidth / 1.5,
child: AppleSignInButton(
style: ButtonStyle.black,
type: ButtonType.continueButton,
onPressed: () {
initiateSignInWithApple();
},
),
),
// you can add code to only show the button when supportsAppleSignIn == true

Almost done, now we need code to sign the user in. (from now on, you have to place every code in the function: ‘initiateSignInWithApple();’

First, we perform the request, a pop up from Apple will show the user what Sign in with apple is, if they want to use a different name or mail…

Note that the requestedScopes are email and fullName.

final AuthorizationResult result = await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);

Then we need to know what happened, did the user cancelled it or succeed, or was there an error?

switch (result.status) {
case AuthorizationStatus.authorized:

// here we're going to sign in the user within firebase
break;
case AuthorizationStatus.error:
// do something
break;

case AuthorizationStatus.cancelled:
print('User cancelled');
break;
}

So if we have AuthorizationStatus.authorized, we can sign in with firebase.

print("successfull sign in");
final AppleIdCredential appleIdCredential = result.credential;

OAuthProvider oAuthProvider =
new OAuthProvider(providerId: "apple.com");
final AuthCredential credential = oAuthProvider.getCredential(
idToken:
String.fromCharCodes(appleIdCredential.identityToken),
accessToken:
String.fromCharCodes(appleIdCredential.authorizationCode),
);

final AuthResult _res = await FirebaseAuth.instance
.signInWithCredential(credential);

FirebaseAuth.instance.currentUser().then((val) async {
UserUpdateInfo updateUser = UserUpdateInfo();
updateUser.displayName =
"${appleIdCredential.fullName.givenName} ${appleIdCredential.fullName.familyName}";
updateUser.photoUrl =
"define a photo url here";
await val.updateProfile(updateUser);
});

As you can see: I update the firebase user right after making it, that’s because the user that’s been made doens’t have a displayName or a photoUrl. So we need to update the user to add the name that we got from Apple.

If you succeeded al these steps, you’re done! You did it!

Thanks for reading!

This is the full code for initiateSignInWithApple();

try {

final AuthorizationResult result = await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);

switch (result.status) {
case AuthorizationStatus.authorized:
try {
print("successfull sign in");
final AppleIdCredential appleIdCredential = result.credential;

OAuthProvider oAuthProvider =
new OAuthProvider(providerId: "apple.com");
final AuthCredential credential = oAuthProvider.getCredential(
idToken:
String.fromCharCodes(appleIdCredential.identityToken),
accessToken:
String.fromCharCodes(appleIdCredential.authorizationCode),
);

final AuthResult _res = await FirebaseAuth.instance
.signInWithCredential(credential);

FirebaseAuth.instance.currentUser().then((val) async {
UserUpdateInfo updateUser = UserUpdateInfo();
updateUser.displayName =
"${appleIdCredential.fullName.givenName} ${appleIdCredential.fullName.familyName}";
updateUser.photoUrl =
"define an url";
await val.updateProfile(updateUser);
});

} catch (e) {
print("error");
}
break;
case AuthorizationStatus.error:
// do something
break;

case AuthorizationStatus.cancelled:
print('User cancelled');
break;
}
} catch (error) {
print("error with apple sign in");
}

--

--