facebook / facebook-sdk-for-unity

The facebook sdk for unity.
https://developers.facebook.com/docs/unity
Other
487 stars 257 forks source link

With Apple ATT refused by user, Facebook classic login fallback in a limited login and returns a non valid authentication token #721

Open Jaeger87 opened 4 months ago

Jaeger87 commented 4 months ago

Checklist

Environment

Describe your dev environment here, giving as many details as possible. If you have them, make sure to include:

Goals

To know if a user is authenticated with classic or limited login.

Expected Results

If facebook classic login fallback to limit login, I expect access_token to be null and not populated with a no valid access_token

Actual Results

When the sdk fallback to limited login, access_token is populated with a non valid token.

Steps to Reproduce

Refuse or not accept ATT, then login with FB.LogInWithReadPermissions(permissions, resultHandler)

saltlevent commented 4 months ago

I have the same issue and i think facebook couldn't fix this issue, and i can't fixed this. Facebook is regret.

@Jaeger87 if you find a solution please let me know.

PierrePlayrion commented 3 months ago

Currently facing the same issue, and it was not happening before we upgraded to 17.0.2. If you guys find a workaround, please share it 🙏

saltlevent commented 3 months ago

Currently facing the same issue, and it was not happening before we upgraded to 17.0.2. If you guys find a workaround, please share it 🙏

I found a solution. Actually it's the only solution i found. You have to downgrade the facebook sdk version. I chose 16.0.2 and it worked. After downgrading the version, sdk works properly and had no problem so far.

PierrePlayrion commented 2 months ago

I found a solution. Actually it's the only solution i found. You have to downgrade the facebook sdk version. I chose 16.0.2 and it worked. After downgrading the version, sdk works properly and had no problem so far.

But I assume that you would have difficulties submitting any build through the app store without the privacy manifest required by Apple (and added in 17.0.0), unless you're adding this yourself (In that case, that could be a solution).

I found that in case of ATT begin opt out, we need to use the Limited Login. I wasn't able to test it to confirm it works.

Maybe someone can confirm this 😄

saltlevent commented 2 months ago

I added my privacy policy by myself via my own website. In 17.0.0 version, facebook login redirecting to the limited.facebook domain. Now its working correctly and app is now on the store (iOS and android)

JimboA commented 2 months ago

I added my privacy policy by myself via my own website. In 17.0.0 version, facebook login redirecting to the limited.facebook domain. Now its working correctly and app is now on the store (iOS and android)

Can you please tell me what your login method looks like now? Is it still through FB.LogInWithReadPermissions or now through FB.Mobile.LoginWithTrackingPreference? We also have SDK version 17.0.0, but att reject still blocks the user from logging in. It is not very clear whether the login code needs to be changed.

saltlevent commented 2 months ago

My login methot is this:

public void LoginFacebook() { var perms = new List() { "public_profile", "email" }; FB.LogInWithReadPermissions(perms, AuthCallback); }

JimboA commented 2 months ago

My login methot is this:

public void LoginFacebook() { var perms = new List() { "public_profile", "email" }; FB.LogInWithReadPermissions(perms, AuthCallback); }

Thank you!) And it's working even if user refuse att? With sdk version 17.0.0 am I understanding correctly? If so it's strange because in our case it's not working( Did you do any additional things?

saltlevent commented 2 months ago

All i did was downgrading the version of the facebook sdk to 16. Maybe you can check the keystore sha. facebook sdk cant encyript the sha with editor tool sometimes. Use keytool and openssl to generate the keystore hash by yourself.

mtemnikov commented 1 month ago

We are struggling the same issue. And downgrading to 16.0.2 is not an option. Any other suggestions?

kiyakkoray commented 1 month ago

We are struggling the same issue. And downgrading to 16.0.2 is not an option. Any other suggestions?

Problems still persist, they seem to have abandoned the SDK completely. This is a direct result of a large number of employees being laid off.

MrLijan commented 1 month ago

@Jaeger87 I tried implement that with unity 2021 and SDK latest version (17.0.1) and I really didn't understand how they expects my application login flow should run. In case the user logged in via the classic method and then switch ATT after a few sessions. How I can "downgrade" the user to the limited without actually asking for a new login process ?

mtemnikov commented 1 month ago

Hello, we changed old login route to limit login route and it worked fine. Be aware that backend validation has also been changed.

MrLijan commented 1 month ago

Hello, we changed old login route to limit login route and it worked fine. Be aware that backend validation has also been changed.

How do you switch between them? How does your code runs when user logged in with limited and then allowing tracking? Or the opposite way

mtemnikov commented 1 month ago

Hello, we changed old login route to limit login route and it worked fine. Be aware that backend validation has also been changed.

How do you switch between them? How does your code runs when user logged in with limited and then allowing tracking? Or the opposite way

We are switching between them on different platforms: using old login on android and new on ios.

Here is the code for ios part:

        private void Authorize()
        {
            if (FB.IsLoggedIn)
            {
                try
                {
                    AuthenticationToken currentToken = FB.Mobile.CurrentAuthenticationToken();
                    if (currentToken != null)
                    {
                        DateTime expirationDateTimeUTC = GetExpirationDateTime(currentToken.TokenString);
                        if (expirationDateTimeUTC > DateTime.UtcNow)
                        {
                            Logger.Log($"[FB] Using received early token");
                            TryHandleToken(currentToken);
                            return;
                        }
                    }
                }
                catch (Exception e) 
                {
                    Debug.LogException(e);
                }
            }
            List<string> permissions = new List<string>()
            {
                "public_profile"
            };
            if (_requirements.RequestEmail)
            {
                permissions.Add("email");
            }
            FB.Mobile.LoginWithTrackingPreference(LoginTracking.LIMITED, permissions, "nonce_stub", HandleAuthorized);
        }

        private void HandleAuthorized(ILoginResult result)
        {
            if (result == null)
            {
                Debug.LogError($"[FB] Received null result. Trying to use old token");
                AuthenticationToken oldToken = FB.Mobile.CurrentAuthenticationToken();
                TryHandleToken(oldToken);
                return;
            }
            Logger.Log($"[FB] Raw result {result.RawResult}");
            if (!string.IsNullOrEmpty(result.Error))
            {
                HandleError(result.Error, result.RawResult);
                return;
            }
            if (result.Cancelled)
            {
                PlatformAuthorizationResult authResult = new PlatformAuthorizationResult(AuthorizationModule.Facebook, Result.Canceled, string.Empty, null);
                HandleResult(authResult);
                return;
            }
            TryHandleToken(result.AuthenticationToken);
        }

        private void TryHandleToken(AuthenticationToken token)
        {
            Profile profile = FB.Mobile.CurrentProfile();
            if (profile == null) 
            {
                HandleError($"No fb profile", string.Empty);
                return;
            }
            FacebookCredentials credentials = ProvideCredentials(token, profile);
            PlatformAuthorizationResult authResult = new(AuthorizationModule.Facebook, Result.Success, string.Empty, credentials);
            HandleResult(authResult);
        }

        private DateTime GetExpirationDateTime(string token)
        {

            string[] parts = token.Split('.');
            if (parts.Length != 3)
            {
                throw new ArgumentException("Invalid token format");
            }

            string payload = parts[1];
            byte[] jsonBytes = Convert.FromBase64String(DecodeBase64Url(payload));
            string json = Encoding.UTF8.GetString(jsonBytes);

            JObject jObject = JObject.Parse(json);

            if (jObject.TryGetValue("exp", out var expToken))
            {
                long expUnixTime = expToken.ToObject<long>();
                DateTime expirationDate = DateTimeOffset.FromUnixTimeSeconds(expUnixTime).UtcDateTime;
                return expirationDate;
            }
            throw new InvalidOperationException($"Unable to find exp field at JWT payload");
        }
        private string DecodeBase64Url(string base64Url)
        {
            return base64Url.Replace('-', '+').Replace('_', '/') + new string('=', (4 - base64Url.Length % 4) % 4);
        }