public Task <BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
        {
            var wait = new TaskCompletionSource <BrowserResult>();

            _sf = new SFAuthenticationSession(
                new NSUrl(options.StartUrl),
                options.EndUrl,
                (callbackUrl, error) =>
            {
                if (error != null)
                {
                    var errorResult = new BrowserResult
                    {
                        ResultType = BrowserResultType.UserCancel,
                        Error      = error.ToString()
                    };

                    wait.SetResult(errorResult);
                }
                else
                {
                    var result = new BrowserResult
                    {
                        ResultType = BrowserResultType.Success,
                        Response   = callbackUrl.AbsoluteString
                    };

                    wait.SetResult(result);
                }
            });

            _sf.Start();
            return(wait.Task);
        }
コード例 #2
0
        static async Task BeginAuthentication(UIViewController presentingController, WebAuthenticator authenticator)
        {
            try {
                var    uri         = (await authenticator.GetInitialUrl());
                string redirectUrl = uri.GetParameter("redirect_uri");
                var    scheme      = new Uri(redirectUrl).Scheme;
                if (!VerifyHasUrlSchemeOrDoesntRequire(scheme))
                {
                    authenticator.OnError($"Unable to redirect {scheme}, Please add the Url Scheme to the info.plist");
                    return;
                }
                var url = new NSUrl(uri.AbsoluteUri);
                if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    var AuthTask = new TaskCompletionSource <object>();
                    authenticators[scheme] = authenticator;
                    var sf = new SFAuthenticationSession(url, scheme,
                                                         (callbackUrl, Error) => {
                        if (Error == null)
                        {
                            ResumeAuth(callbackUrl.AbsoluteString);
                            AuthTask.SetResult(null);
                        }
                        else
                        {
                            AuthTask.SetException(new Exception($"SFAuthenticationSession Error: {Error.ToString()}"));
                        }
                    }
                                                         );
                    sf.Start();
                    await AuthTask.Task;
                    return;
                }

                if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0))
                {
                    var controller = new SFSafariViewController(url, false)
                    {
                        Delegate = new NativeSFSafariViewControllerDelegate(authenticator),
                    };
                    authenticators [scheme] = authenticator;
                    CurrentController       = controller;
                    await presentingController.PresentViewControllerAsync(controller, true);

                    return;
                }

                var opened = UIApplication.SharedApplication.OpenUrl(url);
                if (!opened)
                {
                    authenticator.OnError("Error opening Safari");
                }
                else
                {
                    authenticators [scheme] = authenticator;
                }
            } catch (Exception ex) {
                authenticator.OnError(ex.Message);
            }
        }
        public void Authenticate(Uri authorizationUri, Uri redirectUri, RequestContext requestContext)
        {
            try
            {
                if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
                {
                    asWebAuthenticationSession = new AuthenticationServices.ASWebAuthenticationSession(new NSUrl(authorizationUri.AbsoluteUri),
                                                                                                       redirectUri.Scheme, (callbackUrl, error) =>
                    {
                        if (error != null)
                        {
                            ProcessCompletionHandlerError(error);
                        }
                        else
                        {
                            ContinueAuthentication(callbackUrl.ToString());
                        }
                    });

                    asWebAuthenticationSession.Start();
                }

                else if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    sfAuthenticationSession = new SFAuthenticationSession(new NSUrl(authorizationUri.AbsoluteUri),
                                                                          redirectUri.Scheme, (callbackUrl, error) =>
                    {
                        if (error != null)
                        {
                            ProcessCompletionHandlerError(error);
                        }
                        else
                        {
                            ContinueAuthentication(callbackUrl.ToString());
                        }
                    });

                    sfAuthenticationSession.Start();
                }

                else
                {
                    safariViewController          = new SFSafariViewController(new NSUrl(authorizationUri.AbsoluteUri), false);
                    safariViewController.Delegate = this;
                    viewController.InvokeOnMainThread(() =>
                    {
                        viewController.PresentViewController(safariViewController, false, null);
                    });
                }
            }
            catch (Exception ex)
            {
                requestContext.Logger.ErrorPii(ex);
                throw MsalExceptionFactory.GetClientException(
                          CoreErrorCodes.AuthenticationUiFailedError,
                          "Failed to invoke SFSafariViewController",
                          ex);
            }
        }
コード例 #4
0
        public async Task <BrowserResult> InvokeAsync(BrowserOptions options)
        {
            var tcs = new TaskCompletionSource <BrowserResult>();

            await InvokeBeforeAuthzRequestHooksAsync(options.StartUrl);

            async void completionHandler(NSUrl url, NSError error)
            {
                session = null;
                if (url == null)
                {
                    await InvokeAfterAuthzResponseHooksAsync(null, "UserCancel");

                    tcs.SetResult(new BrowserResult {
                        ResultType = BrowserResultType.UserCancel
                    });
                }
                else
                {
                    var response = url.AbsoluteString;
                    if (!response.StartsWith(RedirectUri + "#") && !response.StartsWith(RedirectUri + "?"))
                    {
                        await InvokeAfterAuthzResponseHooksAsync(null, response);

                        tcs.SetResult(new BrowserResult {
                            ResultType = BrowserResultType.UnknownError
                        });
                    }
                    await InvokeAfterAuthzResponseHooksAsync(response, null);

                    tcs.SetResult(new BrowserResult {
                        ResultType = BrowserResultType.Success, Response = response
                    });
                }
            }

            if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
            {
                session = new SFAuthenticationSession(new NSUrl(options.StartUrl), CustomUrlScheme, completionHandler);
                session.Start();
            }
            else
            {
                SafariViewDelegate.GetInstance().Start(new NSUrl(options.StartUrl), CustomUrlScheme, completionHandler);
            }
            return(await tcs.Task);
        }
        internal static Task <BrowserResult> Start(BrowserOptions options)
        {
            var tcs = new TaskCompletionSource <BrowserResult>();

            SFAuthenticationSession sfWebAuthenticationSession = null;

            sfWebAuthenticationSession = new SFAuthenticationSession(
                new NSUrl(options.StartUrl),
                options.EndUrl,
                (callbackUrl, error) =>
            {
                tcs.SetResult(CreateBrowserResult(callbackUrl, error));
                sfWebAuthenticationSession.Dispose();
            });

            sfWebAuthenticationSession.Start();

            return(tcs.Task);
        }
コード例 #6
0
            static void AuthSessionCallback(NSUrl cbUrl, NSError error)
            {
                if (error == null)
                {
                    OpenUrl(cbUrl);
                }
                else if (error.Domain == asWebAuthenticationSessionErrorDomain && error.Code == asWebAuthenticationSessionErrorCodeCanceledLogin)
                {
                    tcsResponse.TrySetCanceled();
                }
                else if (error.Domain == sfAuthenticationErrorDomain && error.Code == sfAuthenticationErrorCanceledLogin)
                {
                    tcsResponse.TrySetCanceled();
                }
                else
                {
                    tcsResponse.TrySetException(new NSErrorException(error));
                }

                was = null;
                sf  = null;
            }
        public void Authenticate(Uri authorizationUri, Uri redirectUri, RequestContext requestContext)
        {
            try
            {
                if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
                {
                    asWebAuthenticationSession = new AuthenticationServices.ASWebAuthenticationSession(new NSUrl(authorizationUri.AbsoluteUri),
                                                                                                       redirectUri.Scheme, (callbackUrl, error) =>
                    {
                        if (error != null)
                        {
                            ProcessCompletionHandlerError(error);
                        }
                        else
                        {
                            ContinueAuthentication(callbackUrl.ToString());
                        }
                    });

                    asWebAuthenticationSession.BeginInvokeOnMainThread(() =>
                    {
                        if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
                        {
                            // If the presentationContext is missing from the session,
                            // MSAL.NET will pick up an "authentication cancelled" error
                            // With the addition of the presentationContext, .Start() must
                            // be called on the main UI thread
                            asWebAuthenticationSession.PresentationContextProvider =
                                new ASWebAuthenticationPresentationContextProviderWindow();
                        }
                        asWebAuthenticationSession.Start();
                    });
                }

                else if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    sfAuthenticationSession = new SFAuthenticationSession(new NSUrl(authorizationUri.AbsoluteUri),
                                                                          redirectUri.Scheme, (callbackUrl, error) =>
                    {
                        if (error != null)
                        {
                            ProcessCompletionHandlerError(error);
                        }
                        else
                        {
                            ContinueAuthentication(callbackUrl.ToString());
                        }
                    });

                    sfAuthenticationSession.Start();
                }
                else
                {
                    safariViewController = new SFSafariViewController(new NSUrl(authorizationUri.AbsoluteUri), false)
                    {
                        Delegate = this
                    };
                    viewController.InvokeOnMainThread(() =>
                    {
                        viewController.PresentViewController(safariViewController, false, null);
                    });
                }
            }
            catch (Exception ex)
            {
                requestContext.Logger.ErrorPii(ex);
                throw new MsalClientException(
                          MsalError.AuthenticationUiFailedError,
                          ex.Message,
                          ex);
            }
        }
コード例 #8
0
        public async Task <WebAuthenticatorResult> AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions)
        {
            var url         = webAuthenticatorOptions?.Url;
            var callbackUrl = webAuthenticatorOptions?.CallbackUrl;
            var prefersEphemeralWebBrowserSession = webAuthenticatorOptions?.PrefersEphemeralWebBrowserSession ?? false;

            if (!VerifyHasUrlSchemeOrDoesntRequire(callbackUrl.Scheme))
            {
                throw new InvalidOperationException("You must register your URL Scheme handler in your app's Info.plist.");
            }

            // Cancel any previous task that's still pending
            if (tcsResponse?.Task != null && !tcsResponse.Task.IsCompleted)
            {
                tcsResponse.TrySetCanceled();
            }

            tcsResponse = new TaskCompletionSource <WebAuthenticatorResult>();
            redirectUri = callbackUrl;
            var scheme = redirectUri.Scheme;

#if __IOS__
            void AuthSessionCallback(NSUrl cbUrl, NSError error)
            {
                if (error == null)
                {
                    OpenUrlCallback(cbUrl);
                }
                else if (error.Domain == asWebAuthenticationSessionErrorDomain && error.Code == asWebAuthenticationSessionErrorCodeCanceledLogin)
                {
                    tcsResponse.TrySetCanceled();
                }
                else if (error.Domain == sfAuthenticationErrorDomain && error.Code == sfAuthenticationErrorCanceledLogin)
                {
                    tcsResponse.TrySetCanceled();
                }
                else
                {
                    tcsResponse.TrySetException(new NSErrorException(error));
                }

                was = null;
                sf  = null;
            }

            if (OperatingSystem.IsIOSVersionAtLeast(12, 0))
            {
                was = new ASWebAuthenticationSession(WebUtils.GetNativeUrl(url), scheme, AuthSessionCallback);

                if (OperatingSystem.IsIOSVersionAtLeast(13, 0))
                {
                    var ctx = new ContextProvider(WindowStateManager.Default.GetCurrentUIWindow());
                    was.PresentationContextProvider       = ctx;
                    was.PrefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession;
                }
                else if (prefersEphemeralWebBrowserSession)
                {
                    ClearCookies();
                }

                using (was)
                {
                    was.Start();
                    return(await tcsResponse.Task);
                }
            }

            if (prefersEphemeralWebBrowserSession)
            {
                ClearCookies();
            }

            if (OperatingSystem.IsIOSVersionAtLeast(11, 0))
            {
                sf = new SFAuthenticationSession(WebUtils.GetNativeUrl(url), scheme, AuthSessionCallback);
                using (sf)
                {
                    sf.Start();
                    return(await tcsResponse.Task);
                }
            }

            // This is only on iOS9+ but we only support 10+ in Essentials anyway
            var controller = new SFSafariViewController(WebUtils.GetNativeUrl(url), false)
            {
                Delegate = new NativeSFSafariViewControllerDelegate
                {
                    DidFinishHandler = (svc) =>
                    {
                        // Cancel our task if it wasn't already marked as completed
                        if (!(tcsResponse?.Task?.IsCompleted ?? true))
                        {
                            tcsResponse.TrySetCanceled();
                        }
                    }
                },
            };

            currentViewController = controller;
            await WindowStateManager.Default.GetCurrentUIViewController().PresentViewControllerAsync(controller, true);
#else
            var opened = UIApplication.SharedApplication.OpenUrl(url);
            if (!opened)
            {
                tcsResponse.TrySetException(new Exception("Error opening Safari"));
            }
#endif

            return(await tcsResponse.Task);
        }
コード例 #9
0
        public Task <BrowserResult> InvokeAsync(BrowserOptions options)
        {
            if (string.IsNullOrWhiteSpace(options.StartUrl))
            {
                throw new ArgumentException("Missing StartUrl", nameof(options));
            }

            if (string.IsNullOrWhiteSpace(options.EndUrl))
            {
                throw new ArgumentException("Missing EndUrl", nameof(options));
            }

            // must be able to wait for the authentication session to be finished to continue
            // with setting the task result
            var tcs = new TaskCompletionSource <BrowserResult>();

            // For iOS 11, we use the new SFAuthenticationSession
            if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
            {
                // create the authentication session
                _authSession = new SFAuthenticationSession(
                    new NSUrl(options.StartUrl),
                    options.EndUrl,
                    (callbackUrl, error) =>
                {
                    if (error != null)
                    {
                        tcs.SetResult(new BrowserResult
                        {
                            ResultType = BrowserResultType.UserCancel,
                            Error      = error.ToString()
                        });
                    }
                    else
                    {
                        tcs.SetResult(new BrowserResult
                        {
                            ResultType = BrowserResultType.Success,
                            Response   = callbackUrl.AbsoluteString
                        });
                    }
                });

                // launch authentication session
                _authSession.Start();
            }
            else // For pre-iOS 11, we use a normal SFSafariViewController
            {
                // create Safari controller
                _safari = new SFSafariViewController(new NSUrl(options.StartUrl))
                {
                    Delegate = this
                };

                ActivityMediator.MessageReceivedEventHandler callback = null;
                callback = async(response) =>
                {
                    // remove handler
                    ActivityMediator.Instance.ActivityMessageReceived -= callback;

                    if (response == "UserCancel")
                    {
                        tcs.SetResult(new BrowserResult
                        {
                            ResultType = BrowserResultType.UserCancel
                        });
                    }
                    else
                    {
                        // Close Safari
                        await _safari.DismissViewControllerAsync(true);

                        // set result
                        tcs.SetResult(new BrowserResult
                        {
                            Response   = response,
                            ResultType = BrowserResultType.Success
                        });
                    }
                };

                // attach handler
                ActivityMediator.Instance.ActivityMessageReceived += callback;

                // https://forums.xamarin.com/discussion/24689/how-to-acces-the-current-view-uiviewcontroller-from-an-external-service
                var window = UIApplication.SharedApplication.KeyWindow;
                var vc     = window.RootViewController;
                while (vc.PresentedViewController != null)
                {
                    vc = vc.PresentedViewController;
                }

                // launch Safari
                vc.PresentViewController(_safari, true, null);
            }

            // Result for this task will be set in the authentication session
            // completion handler
            return(tcs.Task);
        }
コード例 #10
0
        internal static async Task <WebAuthenticatorResult> PlatformAuthenticateAsync(Uri url, Uri callbackUrl)
        {
            // Cancel any previous task that's still pending
            if (tcsResponse?.Task != null && !tcsResponse.Task.IsCompleted)
            {
                tcsResponse.TrySetCanceled();
            }

            tcsResponse = new TaskCompletionSource <WebAuthenticatorResult>();
            redirectUri = callbackUrl;

            try
            {
                var scheme = redirectUri.Scheme;

                if (!VerifyHasUrlSchemeOrDoesntRequire(scheme))
                {
                    tcsResponse.TrySetException(new InvalidOperationException("You must register your URL Scheme handler in your app's Info.plist!"));
                    return(await tcsResponse.Task);
                }

#if __IOS__
                void AuthSessionCallback(NSUrl cbUrl, NSError error)
                {
                    if (error == null)
                    {
                        OpenUrl(cbUrl);
                    }
                    else
                    {
                        tcsResponse.TrySetException(new NSErrorException(error));
                    }
                }

                if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
                {
                    was = new ASWebAuthenticationSession(new NSUrl(url.OriginalString), scheme, AuthSessionCallback);

                    if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
                    {
                        var ctx = new ContextProvider(Platform.GetCurrentWindow());
                        void_objc_msgSend_IntPtr(was.Handle, ObjCRuntime.Selector.GetHandle("setPresentationContextProvider:"), ctx.Handle);
                    }

                    using (was)
                    {
                        was.Start();
                        return(await tcsResponse.Task);
                    }
                }

                if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    sf = new SFAuthenticationSession(new NSUrl(url.OriginalString), scheme, AuthSessionCallback);
                    using (sf)
                    {
                        sf.Start();
                        return(await tcsResponse.Task);
                    }
                }

                // THis is only on iOS9+ but we only support 10+ in Essentials anyway
                var controller = new SFSafariViewController(new NSUrl(url.OriginalString), false)
                {
                    Delegate = new NativeSFSafariViewControllerDelegate
                    {
                        DidFinishHandler = (svc) =>
                        {
                            // Cancel our task if it wasn't already marked as completed
                            if (!(tcsResponse?.Task?.IsCompleted ?? true))
                            {
                                tcsResponse.TrySetException(new OperationCanceledException());
                            }
                        }
                    },
                };

                currentViewController = controller;
                await Platform.GetCurrentUIViewController().PresentViewControllerAsync(controller, true);

                return(await tcsResponse.Task);
#else
                var opened = UIApplication.SharedApplication.OpenUrl(url);
                if (!opened)
                {
                    tcsResponse.TrySetException(new Exception("Error opening Safari"));
                }
#endif
            }
            catch (Exception ex)
            {
                tcsResponse.TrySetException(ex);
            }

            return(await tcsResponse.Task);
        }
        public void Authenticate(Uri authorizationUri, Uri redirectUri, RequestContext requestContext)
        {
            try
            {
                /* For app center builds, this will need to build on a hosted mac agent. The mac agent does not have the latest SDK's required to build 'ASWebAuthenticationSession'
                 * Until the agents are updated, appcenter build will need to ignore the use of 'ASWebAuthenticationSession' for iOS 12.*/
#if !IS_APPCENTER_BUILD
                if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
                {
                    asWebAuthenticationSession = new AuthenticationServices.ASWebAuthenticationSession(new NSUrl(authorizationUri.AbsoluteUri),
                                                                                                       redirectUri.Scheme, (callbackUrl, error) =>
                    {
                        if (error != null)
                        {
                            ProcessCompletionHandlerError(error);
                        }
                        else
                        {
                            ContinueAuthentication(callbackUrl.ToString());
                        }
                    });

                    asWebAuthenticationSession.Start();
                }

                else if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    sfAuthenticationSession = new SFAuthenticationSession(new NSUrl(authorizationUri.AbsoluteUri),
                                                                          redirectUri.Scheme, (callbackUrl, error) =>
                    {
                        if (error != null)
                        {
                            ProcessCompletionHandlerError(error);
                        }
                        else
                        {
                            ContinueAuthentication(callbackUrl.ToString());
                        }
                    });

                    sfAuthenticationSession.Start();
                }
#else
                if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    sfAuthenticationSession = new SFAuthenticationSession(new NSUrl(authorizationUri.AbsoluteUri),
                                                                          redirectUri.Scheme, (callbackUrl, error) =>
                    {
                        if (error != null)
                        {
                            ProcessCompletionHandlerError(error);
                        }
                        else
                        {
                            ContinueAuthentication(callbackUrl.ToString());
                        }
                    });

                    sfAuthenticationSession.Start();
                }
#endif
                else
                {
                    safariViewController = new SFSafariViewController(new NSUrl(authorizationUri.AbsoluteUri), false)
                    {
                        Delegate = this
                    };
                    viewController.InvokeOnMainThread(() =>
                    {
                        viewController.PresentViewController(safariViewController, false, null);
                    });
                }
            }
            catch (Exception ex)
            {
                requestContext.Logger.ErrorPii(ex);
                throw new MsalClientException(
                          MsalError.AuthenticationUiFailedError,
                          "Failed to invoke SFSafariViewController",
                          ex);
            }
        }
コード例 #12
0
        internal static async Task <AuthResult> NavigateAsync(Uri uri, Uri redirectUri)
        {
            isWaiting = true;

            tcsAuth = new TaskCompletionSource <AuthResult>();
            WebAuthenticator.redirectUri = redirectUri;

            try
            {
                var scheme = redirectUri.Scheme;

                if (!VerifyHasUrlSchemeOrDoesntRequire(scheme))
                {
                    tcsAuth.TrySetException(new InvalidOperationException("You must register your URL Scheme handler in your app's Info.plist!"));
                    return(await tcsAuth.Task);
                }

                if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    var sf = new SFAuthenticationSession(new NSUrl(uri.OriginalString), scheme,
                                                         (callbackUrl, Error) =>
                    {
                        if (Error == null)
                        {
                            UrlOpened(callbackUrl);
                        }
                        else
                        {
                            tcsAuth.TrySetException(new Exception($"SFAuthenticationSession Error: {Error.ToString()}"));
                        }
                    }
                                                         );
                    sf.Start();
                    return(await tcsAuth.Task);
                }

                if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0))
                {
                    var controller = new SFSafariViewController(new NSUrl(uri.OriginalString), false)
                    {
                        Delegate = new NativeSFSafariViewControllerDelegate
                        {
                            DidFinishHandler = delegate
                            {
                                // Cancel our task if it wasn't already marked as completed
                                if (!(tcsAuth?.Task?.IsCompleted ?? true))
                                {
                                    tcsAuth.TrySetException(new OperationCanceledException());
                                }

                                Console.WriteLine("Finished");
                            }
                        },
                    };
                    currentViewController = controller;
                    await Platform.PresentingViewController.PresentViewControllerAsync(controller, true);

                    return(await tcsAuth.Task);
                }

                var opened = UIApplication.SharedApplication.OpenUrl(uri);
                if (!opened)
                {
                    tcsAuth.TrySetException(new Exception("Error opening Safari"));
                }
            }
            catch (Exception ex)
            {
                tcsAuth.TrySetException(ex);
            }

            return(await tcsAuth.Task);
        }
コード例 #13
0
        protected virtual async Task <WebAuthenticationResult> AuthenticateAsyncCore(
            WebAuthenticationOptions options,
            Uri requestUri,
            Uri callbackUri,
            CancellationToken ct)
        {
            var tcs = new TaskCompletionSource <WebAuthenticationResult>();

            void AuthSessionCallback(NSUrl?callbackUrl, NSError?error)
            {
                if (error != null)
                {
                    if ((error.Domain == asWebAuthenticationSessionErrorDomain &&
                         error.Code == asWebAuthenticationSessionErrorCodeCanceledLogin)
#if __IOS__
                        || (error.Domain == sfAuthenticationErrorDomain &&
                            error.Code == sfAuthenticationErrorCanceledLogin)
#endif
                        )
                    {
                        tcs.SetResult(new WebAuthenticationResult(
                                          null,
                                          0,
                                          WebAuthenticationStatus.UserCancel));
                    }
                    tcs.SetResult(new WebAuthenticationResult(
                                      error.ToString(),
                                      0,
                                      WebAuthenticationStatus.ErrorHttp));
                }
                else
                {
                    tcs.SetResult(new WebAuthenticationResult(
                                      callbackUrl?.AbsoluteString,
                                      0,
                                      WebAuthenticationStatus.Success));
                }
            }

            IDisposable?was = default;

            void Cancel()
            {
                var w = was;

                if (w is ASWebAuthenticationSession aswas)
                {
                    aswas.Cancel();
                }
#if __IOS__
                else if (w is SFAuthenticationSession sfwas)
                {
                    sfwas.Cancel();
                }
#endif

                w?.Dispose();
                was = null;
            }

            await using var x = ct.Register(Cancel);

            var startUrl    = new NSUrl(requestUri.OriginalString);
            var callbackUrl = callbackUri.OriginalString;

            var schemes = GetApplicationCustomSchemes().ToArray();
            if (!schemes.Any(s => callbackUrl.StartsWith(s)))
            {
                var message = schemes.Length == 0
                                        ? "No schemes defined in info.plist. You must define a custom scheme (CFBundleURLSchemes) for your callback url."
                                        : $"No schemes defined for callback url {callbackUrl}. Defined schemes are: {schemes.JoinBy(" ")}";
                throw new InvalidOperationException(message);
            }


#if __IOS__
            if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
#else
            var osVersion = NSProcessInfo.ProcessInfo.OperatingSystemVersion;
            if (new Version((int)osVersion.Major, (int)osVersion.Minor) >= new Version(10, 15))
#endif
            {
                var aswas = new ASWebAuthenticationSession(startUrl, callbackUrl, AuthSessionCallback);
                was = aswas;

#if __IOS__
                if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
#endif
                {
                    aswas.PresentationContextProvider       = new PresentationContextProviderToSharedKeyWindow();
                    aswas.PrefersEphemeralWebBrowserSession =
                        WinRTFeatureConfiguration.WebAuthenticationBroker.PrefersEphemeralWebBrowserSession;
                }

                var dispatcher = CoreDispatcher.Main;
                if (dispatcher.HasThreadAccess)
                {
                    Start();
                }
                else
                {
                    var t = dispatcher.RunAsync(CoreDispatcherPriority.Normal, Start);
                }

                void Start()
                {
                    if (!aswas.Start())
                    {
                        tcs.TrySetException(new InvalidOperationException("Unable to start authentication"));
                    }
                }
            }
#if __IOS__
            else
            {
                if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    var sfwas = new SFAuthenticationSession(startUrl, callbackUrl, AuthSessionCallback);
                    was = sfwas;

                    if (!sfwas.Start())
                    {
                        tcs.TrySetException(new InvalidOperationException("Unable to start authentication"));
                    }
                }

                else
                {
                    throw new InvalidOperationException("iOS v11+ is required for this implementation of WebAuthenticationBroker.");
                }
            }
#endif

            try
            {
                return(await tcs.Task);
            }
            finally
            {
                Cancel();
            }
        }