FirebaseUI-iOS icon indicating copy to clipboard operation
FirebaseUI-iOS copied to clipboard

When using Sign In with Apple to create an account displayName value of the auth user is not being set

Open KrisConrad opened this issue 6 years ago • 25 comments

Step 1: Are you in the right place?

  • For issues or feature requests related to the code in this repository file a GitHub issue.
  • For general technical questions, post a question on StackOverflow tagged appropriately.
  • For general Firebase discussion, use the firebase-talk google group
  • For help troubleshooting your application that does not fall under one of the above categories, reach out to the personalized Firebase support channel

Step 2: Describe your environment

  • Objective C or Swift: Swift
  • iOS version: 13
  • Firebase SDK version: 6.14
  • FirebaseUI version: 8.4
  • CocoaPods Version: 1.8.4

Step 3: Describe the problem:

Steps to reproduce:

  1. Sign in using Sign In With Apple for the first time

Observed Results:

  • What happened?

Auth.auth().currentUser?.displayName in nil

Expected Results:

  • What did you expect to happen?

For Auth.auth().currentUser?.displayName to be set to the fullName value of the ASAuthorizationAppleIDCredential passed into the authorizationController:didCompleteWithAuthorization method of the ASAuthorizationControllerDelegate

KrisConrad avatar Dec 16 '19 17:12 KrisConrad

Closing this in favor of https://github.com/firebase/firebase-ios-sdk/issues/4393. We'll continue updating the issue there.

Please let me know if this is actually a different issue.

morganchen12 avatar Dec 16 '19 19:12 morganchen12

@morganchen12 After looking through that issue, I think this is a related, but separate issue.

Unless I'm misunderstanding, the Firebase SDK isn't setting the displayName on the Auth().currentUser because the name is not provided in the ID Token. It looks like the proposed solution in https://github.com/firebase/firebase-ios-sdk/issues/4393 is to update the documentation to inform developers that they will have to update the displayName value in a separate call.

If this is the case it seems like it would then be the responsibility of the FirebaseUI SDK to implement that second call.

let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = displayName
changeRequest?.commitChanges { (error) in
  // ...
}

KrisConrad avatar Dec 17 '19 15:12 KrisConrad

Good point, I'll address that in this library.

morganchen12 avatar Dec 17 '19 19:12 morganchen12

Hi @KrisConrad, could you help me on this,

When using Firebase Auth UI, what all i need to do are:

  • set provider (which is has FUIOAuth.appleAuthProvider())
  • create authViewController
  • call present(authViewController!, animated: true, completion: nil) at final step to open signin screen.

And, there is a protocol named FUIAuthDelegate to get the callback also. What i want to known is how can I deal with didCompleteWithAuthorization in this case. I don't see the connection between them.

langhoangal avatar Jan 09 '20 09:01 langhoangal

Hey @langhoangal, the didCompleteWithAuthorization method will be called if sign in with apple is successful. You should be able to retrieve the user from that callback.

morganchen12 avatar Jan 09 '20 17:01 morganchen12

Good point, I'll address that in this library.

@morganchen12 Hi, wondering if there an ETA to get it done? Thanks!

nex-derek avatar Mar 03 '20 06:03 nex-derek

No, no ETA. :(

morganchen12 avatar Mar 03 '20 17:03 morganchen12

@morganchen12 Apple updated their guidelines and they require Sign-In with Apple starting April 30, 2020 [1].

Are you intending to solve this issue before that date or do still have no ETA? 🤔🙂

[1] https://9to5mac.com/2020/03/04/apple-now-allows-push-notification-advertising-updates-dating-app-review-guidelines-and-more/

IchordeDionysos avatar Mar 06 '20 02:03 IchordeDionysos

I'll aim to solve it before then.

morganchen12 avatar Mar 06 '20 17:03 morganchen12

@morganchen12 , any update on this?

NaturalLam avatar Apr 16 '20 21:04 NaturalLam

@morganchen12 , do you still have target to solve this before Apple's deadline?

NaturalLam avatar May 13 '20 00:05 NaturalLam

Hey, unfortunately I have not been able to resolve this before the deadline. You can work around this by prompting your user for a name or fetching the name via Firebase Auth.

morganchen12 avatar May 13 '20 17:05 morganchen12

@morganchen12 Deadline has been moved to June 30.

https://developer.apple.com/news/?id=03262020b

IchordeDionysos avatar May 13 '20 17:05 IchordeDionysos

@morganchen12 Apple already started enforcing this, do we have plan to fix?

NaturalLam avatar Jul 07 '20 01:07 NaturalLam

I had to ask user for display name after sign in with apple, till this get fixed

iTarek avatar Jul 16 '20 01:07 iTarek

Hey, unfortunately I have not been able to resolve this before the deadline. You can work around this by prompting your user for a name or fetching the name via Firebase Auth.

You can not even fetch the name via Firebase Auth, it's NIL

iTarek avatar Jul 16 '20 02:07 iTarek

This has become more important, Today we got a rejection for our app (see below). I now have a release with a deadline of Monday and not enough time to rip out the FirebaseUI SDK and rewrite our log in flow so we don't have to ask the user for their name:

Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage

We noticed that after users authenticate their account with Sign in with Apple, they are required to take additional steps before they can access content and features in your app. Specifically:

  • Your app requires users to provide their name and/or email address after using Sign in with Apple.

Sign in with Apple is designed to be a self-contained, all-in-one login system. With security features like built-in two-factor authentication, you can remove additional sign-up steps so users can focus on your app's content and features.

KrisConrad avatar Oct 08 '20 23:10 KrisConrad

@rosalyntan Would you mind looking into this?

yuchenshi avatar Oct 12 '20 20:10 yuchenshi

For anyone else who is in desperate need of getting their app through Apple Review and is in need of a (hopefully temporary) solution I'll share what I'm doing.

First I wrote an extension for FUIOAuth to swizzle the delegate method Apple calls when a user successfully signs in with Apple. The auth process with Firebase hasn't finished at the time this method is called so I look for the full name of the user and save it to UserDefaults.

import AuthenticationServices

@available(iOS 13.0, *)
extension FUIOAuth {
    static func swizzleAppleAuthCompletion() {
        let instance = FUIOAuth.appleAuthProvider()
        let originalSelector = NSSelectorFromString("authorizationController:didCompleteWithAuthorization:")
        let swizzledSelector = #selector(swizzledAuthorizationController(controller:didCompleteWithAuthorization:))
        guard let originalMethod = class_getInstanceMethod(instance.classForCoder, originalSelector),
              let swizzledMethod = class_getInstanceMethod(instance.classForCoder, swizzledSelector) else { return }
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }

    @objc func swizzledAuthorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let nameComponents = (authorization.credential as? ASAuthorizationAppleIDCredential)?.fullName {
            let nameFormatter = PersonNameComponentsFormatter()
            let displayName = nameFormatter.string(from: nameComponents)
            UserDefaults.standard.setValue(displayName, forKey: "displayName")
            UserDefaults.standard.synchronize()
        }
        swizzledAuthorizationController(controller: controller, didCompleteWithAuthorization: authorization)
    }
}

Then elsewhere, when setting up the defaultAuthUI I call the function to swizzle the methods above:

        var providers: [FUIAuthProvider] = []

        if #available(iOS 13.0, *) {
            providers.append(FUIOAuth.properAppleAuthProvider)
            FUIOAuth.swizzleAppleAuthCompletion()
        }

        providers += [FUIGoogleAuth(), FUIEmailAuth()]

        FUIAuth.defaultAuthUI()?.providers = providers
        FUIAuth.defaultAuthUI()?.shouldHideCancelButton = true
        FUIAuth.defaultAuthUI()?.customStringsBundle = Bundle.main
        FUIAuth.defaultAuthUI()?.delegate = authDelegate

Lastly, I set up an auth state change listener where I save the displayName on the user's profile and clear out the value from UserDefaults. There could be some more cleanup/error handling here (checking to see a the saved value exists when user.displayName is not nil, checking if commitChanges(_:) returns an error, etc) but this should be the general idea.

        Auth.auth().addStateDidChangeListener { (auth, user) in
            guard let user = user,
                  user.displayName == nil,
                  let displayName = UserDefaults.shared.string(forKey: "displayName") else { return }

            let changeRequest = user.createProfileChangeRequest()
            changeRequest.displayName = displayName
            changeRequest.commitChanges(completion: { (_) in
                UserDefaults.standard.setValue(nil, forKey: "displayName")
                UserDefaults.standard.synchronize()
            })
        }

KrisConrad avatar Oct 15 '20 14:10 KrisConrad

Got another app rejection during an update review because this issue again today. Would be super cool if it was ever fixed.

KrisConrad avatar Jan 14 '21 15:01 KrisConrad

is there any update on this?

Arunperfutil avatar Jan 25 '21 07:01 Arunperfutil

Hey @Arunperfutil, a fix is in review at https://github.com/firebase/FirebaseUI-iOS/pull/933/files and will be released soon.

morganchen12 avatar Jan 25 '21 18:01 morganchen12

This should be fixed in the latest version of FirebaseUI. Please let me know if that's not the case.

morganchen12 avatar Jan 26 '21 20:01 morganchen12

I think I'm still encountering this issue, on the newest version. I'm using the built in defaultAuthUI, with Google, Facebook, Apple, and Email providers. I'm using the following to propagate changes to the app:

        Auth.auth().addStateDidChangeListener { (_, user) in
            print(user)
            print(user?.email)
            print(user?.displayName)
            self.user = user
        }

When I login with apple, I'm getting this in my logs:

Optional(<FIRUser: 0x283395480>)
Optional("<readacted>@gmail.com")
Optional("")

So the email is being persisted, but it looks like the name isn't. Any ideas if this is the same problem?

Even weirder... AFTER logging in with Apple, if I try to go back to logging in with Google or Facebook or something else, I continue receiving an empty string for the display name...

Then, if I go into the Firebase Auth console and delete the user - I can restart and recreate the error

Here's a screen recording showing the issue: https://user-images.githubusercontent.com/15692420/132564881-941ea69e-30c5-4776-a277-ce5744ea21a0.mp4

Highlights:

  1. Started by deleting all users from Firebase console
  2. When logging in with Apple for the first time, user.displayName is nil
  3. After logging out and back into Apple, user.displayName is "" (empty string)
  4. After logging out and back into Apple, user.displayName is, once again, "" (empty string)
  5. After logging out and logging in with Google, user.displayName is "Eric Romrell"
  6. After logging out and back in with Google, user.displayName is "Eric Romrell" again
  7. After logging out and back in with Apple, user.displayName is "Eric Romrell"
  8. After logging out and back in with Apple, user.displayName is back to "" (empty string)
  9. (not included in video) After logging out and back in with Google, user.displayName continues to be "" (empty string).

So, it almost seems like logging in with Apple never gives the name, and ends up corrupting the other auth methods, so that the name is no longer available for any of them (?) @morganchen12 any ideas?

Here's the firebaseui portion of my podfile.lock:

  - FirebaseUI (12.0.2):
    - FirebaseUI/Anonymous (= 12.0.2)
    - FirebaseUI/Auth (= 12.0.2)
    - FirebaseUI/Database (= 12.0.2)
    - FirebaseUI/Email (= 12.0.2)
    - FirebaseUI/Facebook (= 12.0.2)
    - FirebaseUI/Firestore (= 12.0.2)
    - FirebaseUI/Google (= 12.0.2)
    - FirebaseUI/OAuth (= 12.0.2)
    - FirebaseUI/Phone (= 12.0.2)
    - FirebaseUI/Storage (= 12.0.2)

romrell4 avatar Sep 08 '21 16:09 romrell4

My app is getting rejected by Apple Review because of this. I'm going to try @KrisConrad suggestion but would be great if you guys could get this working.

Update - I do believe the changes from https://github.com/firebase/FirebaseUI-iOS/pull/933/files do work in updating the displayName on the user. The problem is that upon first log-in, what I was finding was that my addStateDidChangeListener would be called before the change from changeRequest.commitChanges would be propagated. Or at least that's my best guess.

So what I ended up doing was swizzling as recommended by @KrisConrad, however I am not calling changeRequest.commitChanges and simply storing the displayName on a singleton to be accessed during the first log-in process.

salami avatar Mar 14 '22 01:03 salami

Fixed upstream in Firebase Auth. https://github.com/firebase/firebase-ios-sdk/pull/10068

morganchen12 avatar Mar 27 '23 20:03 morganchen12

So by closing this are we indicating that there should be no required changes within the auth UI library? Not even a version update? Should users of the library just start seeing the display name always populated for Apple login users? Cc @morganchen12

romrell4 avatar Mar 28 '23 01:03 romrell4