parse-community / Parse-SDK-dotNET

Parse SDK for .NET, Xamarin, Unity.
http://parseplatform.org
Apache License 2.0
322 stars 260 forks source link

Sign in with Apple? #347

Closed patkozlowski closed 3 years ago

patkozlowski commented 3 years ago

I have sign in with Facebook implemented with versions 1.7.0, but Apple has recently started to reject Apps for only having only a sign in with Facebook option - at least from my end. I need to implement the sign in with Apple to resolve this. I haven't seen any posts or information on the .Net or Xamarin end regarding this only the native iOS versions of parse. I know looking at the Parse Server end, they do support this, but has been a challenge looking into it with many improvements on the server end. Any information or insight on this would be greatly appreciated.

mtrezza commented 3 years ago

Sign-in with Apple is not implemented in the .NET SDK as a convenience method yet, but you should be able to implement that manually.

Possibly related: https://github.com/parse-community/Parse-SDK-dotNET/issues/335

I'm closing this as it does not seem to be a .NET SDK issue.

For help with Parse Server, here are some resources you can try:

Feel free to comment if you have any questions and we can re-open this issue.

patkozlowski commented 3 years ago

Thanks, implemented it manually, and can confirm it does work.

mtrezza commented 3 years ago

Great! If you feel like sharing your solution and making it part of the .NET SDK, feel free to open a PR and get all the benefits of a community reviewed contribution.

patkozlowski commented 3 years ago

I actually didn't update the SDK itself as I don't have time right now - sorry for the confusion, I used rest requests using RestSharp and handled the login, got the session id, and assigned that session to be the current user. I've seen similar threads doing this for a Twitter login. Seems a bit hacky, but it does work. A more elegant solution is needed, but for me, this will do, and can help somebody out. This is for Xamarin.iOS in the DidComplete (for didCompleteWithAuthorization) method:

`[Export ("authorizationController:didCompleteWithAuthorization:")] public async void DidComplete (ASAuthorizationController controller, ASAuthorization authorization) { if (authorization.GetCredential () is ASAuthorizationAppleIdCredential appleIdCredential) { var userIdentifier = appleIdCredential.User; var fullName = appleIdCredential.FullName; var email = appleIdCredential.Email;

            var rest = new RestSharp.RestClient("https://app.herokuapp.com/parse");
            var req = new RestSharp.RestRequest("/users/", RestSharp.Method.POST);
            req.AddHeader("X-Parse-Application-Id", "app");
            req.AddHeader("X-Parse-Master-Key", "pw");
            req.AddHeader("Content-Type", "application/json");
            var payload = "{ \"authData\": { \"apple\": { ";
            payload += "\"id\": \"" + appleIdCredential.User + "\", ";
            payload += "\"token\": \"" + appleIdCredential.IdentityToken + "\" ";
            payload += "} } }";

            req.AddParameter("application/json", payload, RestSharp.ParameterType.RequestBody);

            RestSharp.IRestResponse res = null;
            var result = await Task<JContainer>.Run(() => {
                res = rest.Execute(req);
                var content = res.Content;
                return JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JContainer>(content);
            });

            InvokeOnMainThread (async() => {

                if ((res.StatusCode == System.Net.HttpStatusCode.OK) || (res.StatusCode == System.Net.HttpStatusCode.Created))
                {
                    var sessionToken = (String)result["sessionToken"];
                    var objectId = (String)result["objectId"];
                    Console.WriteLine(result);

                    req = new RestSharp.RestRequest("/users/" + objectId, RestSharp.Method.PUT);
                    req.AddHeader("X-Parse-Application-Id", "app");
                    req.AddHeader("X-Parse-Master-Key", "pw");
                    req.AddHeader("X-Parse-Session-Token", sessionToken);
                    req.AddHeader("Content-Type", "application/json");
                    result = await Task<JContainer>.Run(() =>
                    {
                        res = rest.Execute(req);
                        var content = res.Content;
                        return JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JContainer>(content);
                    });

                    try
                    {
                        await ParseUser.BecomeAsync(sessionToken);
                    }
                    catch (Exception e)
                    {
                        if (sessionToken == null) //for some reason 1st time logging in, sessionToken is null
                        {
                                var rest1 = new RestSharp.RestClient("https://app.herokuapp.com/parse");
                                var req1 = new RestSharp.RestRequest("/users/", RestSharp.Method.POST);
                                req1.AddHeader("X-Parse-Application-Id", "app");
                                req1.AddHeader("X-Parse-Master-Key", "pw");
                                req1.AddHeader("Content-Type", "application/json");

                                var payload1 = "{ \"authData\": { \"apple\": { ";
                                payload1 += "\"id\": \"" + appleIdCredential.User + "\", ";
                                payload1 += "\"token\": \"" + appleIdCredential.IdentityToken + "\" ";
                                payload1 += "} } }";

                                req1.AddParameter("application/json", payload1, RestSharp.ParameterType.RequestBody);

                                RestSharp.IRestResponse res1 = null;
                                var result1 = await Task<JContainer>.Run(() =>
                                {
                                    res1 = rest.Execute(req1);
                                    var content1 = res1.Content;
                                    return JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JContainer>(content1);
                                });
                                if ((res1.StatusCode == System.Net.HttpStatusCode.OK) || (res1.StatusCode == System.Net.HttpStatusCode.Created))
                                {
                                    var sessionToken1 = (String)result1["sessionToken"];
                                    var objectId1 = (String)result1["objectId"];
                                    Console.WriteLine(result1);
                                    req1 = new RestSharp.RestRequest("/users/" + objectId1, RestSharp.Method.PUT);
                                    req1.AddHeader("X-Parse-Application-Id", "app");
                                    req1.AddHeader("X-Parse-Master-Key", "pw");
                                    req1.AddHeader("X-Parse-Session-Token", sessionToken1);
                                    req1.AddHeader("Content-Type", "application/json");
                                    req1.AddParameter("application/json", "{ \"username\": \"" + email + "\" }", RestSharp.ParameterType.RequestBody);
                                    result1 = await Task<JContainer>.Run(() =>
                                    {
                                        res1 = rest1.Execute(req1);
                                        var content1 = res1.Content;
                                        return JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JContainer>(content1);
                                    });

                                try
                                {
                                    await ParseUser.BecomeAsync(sessionToken1);
                                    ParseUser.CurrentUser.Email = email;
                                    await ParseUser.CurrentUser.SaveAsync();
                                }
                                catch (Exception e1)
                                {
                                    //something went wrong
                                }

                            }
                        }

                    }
                }
                UIStoryboard storyboard = UIStoryboard.FromName("Main", null);

                UIViewController nc = storyboard.InstantiateViewController("ResultViewController"); //"tablesb");
                var appDelegate = UIApplication.SharedApplication.Delegate as AppDelegate;
                appDelegate.Window.RootViewController = nc;

            });
        } 
    }`
mtrezza commented 3 years ago

Thanks for sharing! Maybe this inspires someone to implement this directly in the SDK.