// TODO - consider creating services that group the login provider specific implementations together
        // e.g. a service that can be injected into various places that handles all the facebook specific implementations across different controllers etc
        private async Task <ProviderLoginDetails> GetFacebookProviderLoginDetailsAsync(string facebookToken)
        {
            // Validate the provided data
            if (string.IsNullOrEmpty(facebookToken))
            {
                _logger.LogInformation("Missing Facebook token.");
                return(new ProviderLoginDetails
                {
                    ErrorDetail = new ErrorDetail("facebookToken", "Missing Facebook token.")
                });
            }

            // we need to verify the token first
            // since only Facebook is supported, we default to it, but in the future, this will likely move
            // to a provider-based pattern
            var result = await _facebookGraphService.TokenDebugAsync(facebookToken);

            if (!result.IsValid || string.IsNullOrEmpty(result.UserId))
            {
                _logger.LogTrace("Facebook token validation failed: {0}", result.Error.Message);
                return(new ProviderLoginDetails
                {
                    ErrorDetail = new ErrorDetail("facebookToken", "Facebook token is either invalid or could not be validated.")
                });
            }
            return(new ProviderLoginDetails
            {
                ProviderId = result.UserId,
                ProviderData = null
            });
        }
        public async Task ValidateAsync(ExtensionGrantValidationContext context)
        {
            try
            {
                var token = context.Request.Raw["token"];

                var facebookTokenDebug = await _facebookGraphService.TokenDebugAsync(token);

                if (!facebookTokenDebug.IsValid)
                {
                    var message = (string)facebookTokenDebug.Error.Message;
                    _logger.LogError("FacebookSignIn: invalid token: {0}", message);
                    _appMonitor.LogEvent("LoginFailed", $"FacebookSignIn: invalid token: {message}", new Dictionary <string, string> {
                        { "EventSubType", "InvalidToken" },
                        { "LoginType", "fb-usertoken" }
                    });
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest);
                    return;
                }
                if (facebookTokenDebug.Error != null) // still got another error
                {
                    var message = (string)facebookTokenDebug.Error.Message;
                    _logger.LogError("FacebookSignIn: error validating token: {0}", message);
                    _appMonitor.LogEvent("LoginFailed", $"FacebookSignIn: error validating token: {message}", new Dictionary <string, string> {
                        { "EventSubType", "TokenValidationFailed" },
                        { "LoginType", "fb-usertoken" }
                    });
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest);
                    return;
                }

                var userId = facebookTokenDebug.UserId;
                if (userId == null)
                {
                    return;
                }
                _logger.LogDebug("FacebookSignIn: Signing in: {0}", userId);

                User user = await GetOrCreateUserAsync(userId);

                var claims = await _userClaimsProvider.GetUserClaimsAsync(user);

                context.Result = new GrantValidationResult(user.UserId, "nether-facebook", claims);

                _appMonitor.LogEvent("LoginSucceeded", properties: new Dictionary <string, string> {
                    { "LoginType", "fb-usertoken" }
                });
            }
            catch (Exception ex)
            {
                _logger.LogError("Error in ValidateAsync: {0}", ex);
                _appMonitor.LogError(ex, "Error in ValidateAsync", new Dictionary <string, string> {
                    { "EventType", "LoginFailed" },
                    { "EventSubType", "UnhandledException" },
                    { "LoginType", "fb-usertoken" }
                });
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, ex.Message);
            }
        }