Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrating from ParseFacebookUtils to use Facebook iOS SDK 17 causes login issues #1787

Closed
4 tasks done
chriscborg opened this issue May 3, 2024 · 17 comments
Closed
4 tasks done
Labels
bounty:$100 Bounty applies for fixing this issue (Parse Bounty Program) type:feature New feature or improvement of existing feature

Comments

@chriscborg
Copy link

chriscborg commented May 3, 2024

New Issue Checklist

Issue Description

Due to an error being received when archiving with Xcode 15.3 as described here #1775, I upgraded to the latest Parse iOS SDK and removed the ParseFacebookUtils to use PFUser.logInWithAuthType with Facebook iOS SDK 17 instead with the below sample

        let loginManager = LoginManager()
        loginManager.logOut()
        loginManager.logIn(permissions: ["email", "public_profile"], from: viewController) { result, error in
            if error != nil {
                print(error!.localizedDescription)
            } else if let result = result, result.isCancelled {
                print("Cancelled")
            } else {
                
                if let tokenId = result?.token?.userID,
                   let token = result?.token?.tokenString,
                   let expiry = result?.token?.expirationDate.toFormattedString() {
                    PFUser.logInWithAuthType(inBackground: "facebook", authData: ["id":tokenId,"access_token":token,"expiration_date":expiry]).continueWith { task -> Any? in
                        if (task.error != nil) {
                            self.showLoginError(viewController: viewController)
                        }
                        
                        if let user = task.result {
                          //success
                        }
                        return nil
                    }
                } else {
                    self.showLoginError(viewController: viewController)
                }
            }
        }

The above works with Facebook iOS SDK 16 but not 17. For 17, I started getting an alert to use limited login so I tried making some changes such as the below

   let loginManager = LoginManager()
   loginManager.logOut()
   let configuration = LoginConfiguration(permissions: ["email", "public_profile"], tracking: .enabled)
   loginManager.logIn(viewController: viewController, configuration: configuration) { result in
      ...
   }

The above didn't work anyway and I don't think setting the tracking to limited would ever work since this doesn't provide an access token.

When I try to login, I get the error [Error]: Facebook auth is invalid for this user. (Code: 101, Version: 4.0.1). I'm not sure if this is due to a misconfiguration from my end or an incompatibility with Parse Server itself. Any suggestions on how this should be configured?

This issue might be related to another issue listed on the Facebook SDK here: facebook/facebook-ios-sdk#2384

Steps to reproduce

  • Upgrade Facebook iOS SDK from 16 to 17, as with the SDK version 16 I get the error described in issue #1775

Actual Outcome

I am now getting an error when logging in using Facebook

[Error]: Facebook auth is invalid for this user. (Code: 101, Version: 4.0.1)

Expected Outcome

The migration should be seamless or documented and login with Facebook should work as with previous versions.

Environment

  • macOS: 14.4
  • Xcode: 15.3

Client

  • Parse ObjC SDK version: 4.0.1
Copy link

parse-github-assistant bot commented May 3, 2024

Thanks for opening this issue!

  • 🚀 You can help us to fix this issue faster by opening a pull request with a failing test. See our Contribution Guide for how to make a pull request, or read our New Contributor's Guide if this is your first time contributing.

@chriscborg
Copy link
Author

This issue might be related this issue here on the Facebook SDK. Perhaps parse-server needs to provide support to the new token? facebook/facebook-ios-sdk#2400

@mtrezza mtrezza added the type:feature New feature or improvement of existing feature label May 3, 2024
@mtrezza
Copy link
Member

mtrezza commented May 3, 2024

I started getting an alert to use limited login

Is that a warning or an error that requires you to use Limited Login? From the issue you linked it seems that Limited Login is mandatory due to ATT enforcement, but what when exactly is it mandatory?

@mtrezza mtrezza pinned this issue May 3, 2024
@chriscborg
Copy link
Author

A warning shows up on the Facebook page when logging when the in-app web browser shows up. Upgrading to Facebook SDK 17 is required now since SDK 17 it is the only version that contains the privacy manifest that is now required by Apple. However with SDK 17 came the requirement to implement Limited Login because not doing so would return an invalid access token. If we configure the Facebook Login Manger to limited, the SDK would return a JWT token and if we configure it to enable tracking we get an access token. In my case, since I have tracking disabled on my phone, configuring it to enable tracking won't have an effect, and I suspect most iOS users will face the same issue. However, neither of these two configurations work on Parse as Parse returns [Error]: Facebook auth is invalid for this user. (Code: 101, Version: 4.0.1). I'm not sure if compatibility needs to be added on parse-server to use the JWT token to authenticate users on Parse, keeping mind existing sessions on Parse logged in with Facebook.

@mtrezza
Copy link
Member

mtrezza commented May 3, 2024

Thanks for the explanation. I think support for JWT token would require a change in the Parse Server's Facebook auth adapter as well.

A solution would need to allow for both types of token: the normal login token with app tracking enabled and the JWT token from Limited Login.

@mtrezza mtrezza added the bounty:$100 Bounty applies for fixing this issue (Parse Bounty Program) label May 3, 2024
@mtrezza
Copy link
Member

mtrezza commented May 3, 2024

Note: The bounty scope includes parse-community/parse-server#9117.

@chriscborg
Copy link
Author

Should we open an issue on Parse Server as well with reference to this one? I'm thinking that this most probably has to be addressed there, and it is quite urgent because if an app uses Facebook login with Parse, no further updates to the App Store can be done as it is.

@mtrezza
Copy link
Member

mtrezza commented May 4, 2024

Sure, this may even be a Parse Server only issue. Done with parse-community/parse-server#9117.

@SebC99
Copy link
Contributor

SebC99 commented May 6, 2024

From what I have seen it is just the host facebook.com that has to be changed to wwww.facebook.com to retrieve the JWT keys. The old url is responding with a 301 which is not followed by the jwt-rsa package.
Changing the url seems to work in our case.

@chriscborg
Copy link
Author

chriscborg commented May 6, 2024

@SebC99 This change needs to be done to the parse-server not on iOS correct?

@SebC99
Copy link
Contributor

SebC99 commented May 6, 2024

True
I should have been more precise, it's in the Facebook auth adapter.

@chriscborg
Copy link
Author

This didn't seem to have worked for me, although I don't have any experience with parse-server. I'm not sure if a different implementation is required on parse-server for limited login to work. Do you have a PR which can be opened for this?

@mtrezza
Copy link
Member

mtrezza commented May 6, 2024

From what I have seen it is just the host facebook.com that has to be changed to wwww.facebook.com to retrieve the JWT keys. The old url is responding with a 301 which is not followed by the jwt-rsa package.

@mman could you explain what you changed so that the Parse Server auth adapter supports both types of login tokens, normal and limited login? From what I understand, if a developer switches to limited login, then the woken is a different one. So the auth adapter on the server side should be able to handle both types of tokens, right?

@chriscborg
Copy link
Author

Quick update from my end as I did further troubleshooting by looking into the adapter's implementation, and it seems like switching the host in Facebook adapter to www.facebook.com as @SebC99 suggested did make a difference. However, from iOS, I had to make another change to the authData being passed to pass token instead of access_token, i.e. PFUser.logInWithAuthType(inBackground: "facebook", authData: ["id":profileId,"token":token]) where token is the JWT token passed from limited login. Parse seems to be able to parse and validate the JWT token and I seem to be able to also verify and login with existing Parse users. Passing token instead seems to take a different path. I'm looking at Adapters/Auth/facebook.js:119 here:

function validateAuthData(authData, options) {
  if (authData.token) {
    return verifyIdToken(authData, options);
  } else {
    return validateGraphToken(authData, options);
  }
}

However I still need to test authentication with tracking enabled and I still need to check how I can retrieve the user's Facebook platform data and store that on Parse as I don't think this is possible from the backend side with this token, but needs to be done client side. I also think that iOS needs to be able to detect a way that tracking is enabled to also to identify if access_token or token should be passed, depending on if the user is using limited login or not.

@chriscborg
Copy link
Author

With the change recommended above, I could get the iOS SDK working using the below implementation. I'm checking if the user has tracking enabled and if an access token is provided by the Facebook SDK in order to determine what to pass to Parse Server. I could then retrieve user information using the Facebook SDK Profile to save these to the Parse User. Do you agree with this implementation? I will open a PR on parse-server with the required change soon and will attempt to update the docs as well.

        //login with facebook
        let loginManager = LoginManager()
        loginManager.logOut()
        //use .limited or .enabled. enabled might give access token if allowed by used
        let configuration = LoginConfiguration(permissions: ["email", "public_profile"], tracking: .enabled)
        loginManager.logIn(viewController: viewController, configuration: configuration) { result in
            switch result {
            case .failed(let error):
                print(error.localizedDescription)
            case .cancelled:
                print("Cancelled")
            case .success:
                
                if let profile = Profile.current,
                   let authToken = AuthenticationToken.current {
                    
                    //limited login
                    let userId = profile.userID
                    let token = authToken.tokenString
                    var authData = ["id":userId, "token":token]
                    
                    //login with tracking enabled
                    if let accessToken = AccessToken.current,
                       ATTrackingManager.trackingAuthorizationStatus == .authorized {
                        let token = accessToken.tokenString
                        let expiry = accessToken.expirationDate.toFormattedString()
                        authData = ["id":userId, "access_token":token, "expiration_date":expiry]
                    }
                    
                    //login with parse
                    PFUser.logInWithAuthType(inBackground: "facebook", authData: authData).continueWith { task -> Any? in
                        if let profile = Profile.current {
            
                            if let email = profile.email {
                                PFUser.current()?.email = email
                            }
            
                            if let name = profile.name {
                                PFUser.current()?.setValue(name, forKey: "name")
                            }
            
                            PFUser.current()?.saveInBackground(block: { (success, error) in
                                ...
                            })
                        }
                }
         }

@mtrezza
Copy link
Member

mtrezza commented May 15, 2024

I agree with your implementation, also see parse-community/parse-server#9117 (comment).

@mtrezza
Copy link
Member

mtrezza commented May 17, 2024

Closing via parse-community/parse-server#9117

@mtrezza mtrezza closed this as completed May 17, 2024
@mtrezza mtrezza unpinned this issue Jun 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bounty:$100 Bounty applies for fixing this issue (Parse Bounty Program) type:feature New feature or improvement of existing feature
Projects
None yet
Development

No branches or pull requests

3 participants