signInWithApple method

Future<FirebaseAuthenticationResult> signInWithApple({
  1. required String? appleRedirectUri,
  2. required String? appleClientId,
  3. bool askForFullName = true,
})

Apple will reject your app if you ask for the name when you sign in, but do not use it in the app. To prevent this, set askForFullName to false.

Implementation

Future<FirebaseAuthenticationResult> signInWithApple({
  required String? appleRedirectUri,
  required String? appleClientId,
  bool askForFullName = true,
}) async {
  try {
    if (appleClientId == null) {
      throw FirebaseAuthException(
        message:
            'If you want to use Apple Sign In you have to provide a appleClientId to the FirebaseAuthenticationService',
        code: StackedFirebaseAuthAppleClientIdMissing,
      );
    }

    if (appleRedirectUri == null) {
      throw FirebaseAuthException(
        message:
            'If you want to use Apple Sign In you have to provide a appleRedirectUri to the FirebaseAuthenticationService',
        code: StackedFirebaseAuthAppleClientIdMissing,
      );
    }

    // To prevent replay attacks with the credential returned from Apple, we
    // include a nonce in the credential request. When signing in in with
    // Firebase, the nonce in the id token returned by Apple, is expected to
    // match the sha256 hash of `rawNonce`.
    final rawNonce = generateNonce();
    final nonce = sha256ofString(rawNonce);

    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
      scopes: [
        AppleIDAuthorizationScopes.email,
        if (askForFullName) AppleIDAuthorizationScopes.fullName,
      ],
      webAuthenticationOptions: WebAuthenticationOptions(
        clientId: appleClientId,
        redirectUri: Uri.parse(appleRedirectUri),
      ),
      nonce: nonce,
    );

    final oAuthProvider = OAuthProvider('apple.com');
    final credential = oAuthProvider.credential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
      rawNonce: rawNonce,
    );

    final appleCredential = await _signInWithCredential(credential);

    // Link the pending credential with the existing account
    if (_pendingCredential != null) {
      await appleCredential.user?.linkWithCredential(_pendingCredential!);

      _clearPendingData();
    }

    if (askForFullName) {
      // Update the display name using the name from
      final givenName = appleIdCredential.givenName;
      final hasGivenName = givenName != null;
      final familyName = appleIdCredential.familyName;
      final hasFamilyName = familyName != null;

      // print('Apple Sign in complete: ${appleIdCredential.toString()}');

      await appleCredential.user?.updateDisplayName(
          '${hasGivenName ? givenName : ''}${hasFamilyName ? ' $familyName' : ''}');
    }

    return FirebaseAuthenticationResult(user: appleCredential.user);
  } on FirebaseAuthException catch (e) {
    log?.e(e);
    return FirebaseAuthenticationResult.error(
      errorMessage: getErrorMessageFromFirebaseException(e),
      exceptionCode: e.code,
    );
  } on SignInWithAppleAuthorizationException catch (e) {
    return FirebaseAuthenticationResult.error(
      errorMessage: e.toString(),
      exceptionCode: e.code.name,
    );
  } catch (e) {
    log?.e(e);
    return FirebaseAuthenticationResult.error(errorMessage: e.toString());
  }
}