Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASAuthorizationAppleIDRequest with name and mail scope returns nil values

I'm implementing Sign in with Apple and noticed that the email and fullName properties of the returned ASAuthorizationAppleIDCredential are only filled on the very first Sign-In for this Apple ID. On all subsequent Sign-Ins those properties are nil.

Is this a bug on iOS 13 or expected behaviour?

Here is the code I'm using to start the request:

@available(iOS 13.0, *)
dynamic private func signInWithAppleClicked() {
    let request = ASAuthorizationAppleIDProvider().createRequest()
    request.requestedScopes = [.fullName, .email]

    let controller = ASAuthorizationController(authorizationRequests: [request])
    controller.delegate = self
    controller.presentationContextProvider = self
    controller.performRequests()
}

I'm receiving the credential in this delegate method:

public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else { return }

    let userIdentifier = credential.user
    let token = credential.identityToken
    let authCode = credential.authorizationCode
    let realUserStatus = credential.realUserStatus
    let mail = credential.email // nil
    let name = credential.fullName // nil
}
like image 808
mhaddl Avatar asked Aug 21 '19 13:08

mhaddl


3 Answers

Seems like a bug but after reading different posts on apple forums it looks like this seems to be the expected behaviour.

So some takeaways.

  1. On the first time sign in with apple (signup) make sure to create user account on your backend.
  2. In case of any connection error with your servers, make sure you save the user details locally (because you are not getting this next time) and keep retrying to create account on your backend.

  3. For testing on device you can revoke your apple ID login for your app. After revoking it will work like a signup next time and you will get the details like (email, name, etc).

To revoke access on your device with IOS 13.

iPhone Settings > Apple Id > Password & Security > Apple ID logins > {YOUR APP} > Stop using Apple ID
like image 105
Bilal Avatar answered Nov 22 '22 14:11

Bilal


In case you're wondering how to retrieve email second and subsequent times, here's a hint: use identityToken which contains encoded in JWT user authorisation data including email.

  1. Import this library to decode JWT: https://github.com/auth0/JWTDecode.swift
  2. try this code
    import JWTDecode
    // ...
    if let identityTokenData = appleIDCredential.identityToken,
    let identityTokenString = String(data: identityTokenData, encoding: .utf8) {
    print("Identity Token \(identityTokenString)")
    do {
       let jwt = try decode(jwt: identityTokenString)
       let decodedBody = jwt.body as Dictionary<String, Any>
       print(decodedBody)
       print("Decoded email: "+(decodedBody["email"] as? String ?? "n/a")   )
    } catch {
       print("decoding failed")
    }

Or decode it at PHP backend like this:

    print_r(json_decode(base64_decode(str_replace('_', '/', str_replace('-','+',explode('.', $identityTokenString)[1])))));
like image 41
Ilya Shevyryaev Avatar answered Nov 22 '22 15:11

Ilya Shevyryaev


It is a correct behavior when implementing SignIn with Apple.

This behaves correctly, user info is only sent in the ASAuthorizationAppleIDCredential upon initial user sign up. Subsequent logins to your app using Sign In with Apple with the same account do not share any user info and will only return a user identifier in the ASAuthorizationAppleIDCredential. It is recommended that you securely cache the initial ASAuthorizationAppleIDCredential containing the user info until you can validate that an account has successfully been created on your server.

To overcome this issue we can store all the required information in Keychain. I have created Singleton class for SignIn With Apple. I am sure it will help you.

Git source: https://github.com/IMHitesh/HSAppleSignIn

You need to follow below steps:

Step:1

Add the AppleSignIn folder into your project.

Step:2

Enable SignIn with Apple in Capabilities.

Step:3 -> IMPORTANT

Goto your UIViewController and Add Container view for SignIn with apple.

if #available(iOS 13.0, *) {
    appleSignIn.loginWithApple(view:viewAppleButton, completionBlock: { (userInfo, message) in
        if let userInfo = userInfo{
            print(userInfo.email)
            print(userInfo.userid)
            print(userInfo.firstName)
            print(userInfo.lastName)
            print(userInfo.fullName)
        }else if let message = message{
            print("Error Message: \(message)")
        }else{
            print("Unexpected error!")
        }
    })
}else{
    viewAppleButton.isHidden = true
}
like image 44
Hitesh Surani Avatar answered Nov 22 '22 14:11

Hitesh Surani