private static async Task <User> GetGoogleUserInfo(ExternalLoginDetails externalLoginInfo)
        {
            ExternalEmailSecret googleSecrets = AppConst.Settings.ExternalLoginSecrets.FindObj(e => e.Provider.EqualCurrentCultureIgnoreCase("Google"));
            var caller  = new HttpClient();
            var content = new StringContent($"client_id={googleSecrets?.ClientId}&client_secret={googleSecrets?.ClientSecret}&code={externalLoginInfo.Code}&grant_type=authorization_code&redirect_uri={externalLoginInfo.RedirectUrl.ToLower()}");

            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            // get the token from github API by using the provided "code", "state", "clientId" and "clientSecret".
            var tokenResult = await caller.PostAsync("https://oauth2.googleapis.com/token", content).ConfigureAwait(false);

            var    tokenResultArray = JsonConvert.DeserializeObject <dynamic>(await tokenResult.Content.ReadAsStringAsync().ConfigureAwait(false));
            string tokenType        = tokenResultArray.token_type;
            string accessToken      = tokenResultArray.access_token;

            // Add the authorization information from the response above
            caller.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
            caller.DefaultRequestHeaders.Add("User-Agent", "OSnack");
            // get the user info by calling the github API with the above authorization
            var userInfoResult = await caller.GetAsync($"https://www.googleapis.com/oauth2/v2/userinfo").ConfigureAwait(false);

            var userInfoResultString = await userInfoResult.Content.ReadAsStringAsync().ConfigureAwait(false);

            var userInfoObj = JsonConvert.DeserializeObject <dynamic>(userInfoResultString);

            return(new User
            {
                Email = (string)userInfoObj.email,
                FirstName = (string)userInfoObj.given_name,
                Surname = (string)userInfoObj.family_name,
                RegistrationMethod = new RegistrationMethod
                {
                    ExternalLinkedId = (string)userInfoObj.id,
                    RegisteredDate = DateTime.UtcNow,
                    Type = externalLoginInfo.Type,
                }
            });
        }
        private static async Task <User> GetFacebookUserInfo(ExternalLoginDetails externalLoginInfo)
        {
            ExternalEmailSecret facebookSecrets = AppConst.Settings.ExternalLoginSecrets.FindObj(e => e.Provider.EqualCurrentCultureIgnoreCase("Facebook"));

            var caller = new HttpClient();
            // get the token from github API by using the provided "code", "state", "clientId" and "clientSecret".
            var tokenResult = await caller.GetAsync($"https://graph.facebook.com/v7.0/oauth/access_token?client_id={facebookSecrets?.ClientId}&redirect_uri={externalLoginInfo.RedirectUrl}&client_secret={facebookSecrets?.ClientSecret}&code={externalLoginInfo.Code}").ConfigureAwait(false);

            var    tokenResultArray = JsonConvert.DeserializeObject <dynamic>(await tokenResult.Content.ReadAsStringAsync().ConfigureAwait(false));
            string tokenType        = tokenResultArray.token_type;
            string accessToken      = tokenResultArray.access_token;

            // Add the authorization information from the response above
            caller.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
            caller.DefaultRequestHeaders.Add("User-Agent", "OSnack");

            // get the user info by calling the github API with the above authorization
            var userInfoResult = await caller.GetAsync($"https://graph.facebook.com/me?fields=id,email,first_name,last_name&access_token={accessToken}").ConfigureAwait(false);

            var userInfoResultString = await userInfoResult.Content.ReadAsStringAsync().ConfigureAwait(false);

            var userInfoObj = JsonConvert.DeserializeObject <dynamic>(userInfoResultString);

            return(new User
            {
                FirstName = (string)userInfoObj.first_name,
                Surname = (string)userInfoObj.last_name,
                Email = (string)userInfoObj.email,
                RegistrationMethod = new RegistrationMethod
                {
                    ExternalLinkedId = (string)userInfoObj.id,
                    RegisteredDate = DateTime.UtcNow,
                    Type = externalLoginInfo.Type,
                }
            });
        }
        public async Task <IActionResult> ExternalLogin(ExternalLoginDetails externalLoginInfo)
        {
            try
            {
                IEnumerable <string> policies = AppFunc.GetCurrentRequestPolicies(Request, out AppTypes apptype);
                if (apptype == AppTypes.Invalid)
                {
                    CoreFunc.Error(ref ErrorsList, "Unauthorised Application Access. 🤔");
                    return(Unauthorized(ErrorsList));
                }

                if (!TryValidateModel(externalLoginInfo))
                {
                    CoreFunc.ExtractErrors(ModelState, ref ErrorsList);
                    return(UnprocessableEntity(ErrorsList));
                }

                User externalLoginUser = new User();
                switch (externalLoginInfo.Type)
                {
                case RegistrationTypes.Google:
                    externalLoginUser = await GetGoogleUserInfo(externalLoginInfo).ConfigureAwait(false);

                    break;

                case RegistrationTypes.Facebook:
                    externalLoginUser = await GetFacebookUserInfo(externalLoginInfo).ConfigureAwait(false);

                    break;
                }

                // Check if the user is already registered
                User registeredUser = await _DbContext.Users
                                      .Include(u => u.Role)
                                      .Include(u => u.RegistrationMethod)
                                      .SingleOrDefaultAsync(u => u.RegistrationMethod.Type == externalLoginInfo.Type &&
                                                            u.RegistrationMethod.ExternalLinkedId == externalLoginUser.RegistrationMethod.ExternalLinkedId)
                                      .ConfigureAwait(false);

                // if the user is already registered
                if (registeredUser != null)
                {
                    if (!await IsUserPolicyAccepted(registeredUser, policies).ConfigureAwait(false))
                    {
                        CoreFunc.Error(ref ErrorsList, "You do not have permission to login here.");
                        return(Unauthorized(ErrorsList));
                    }

                    // sign the user in without any password
                    await _SignInManager.SignInAsync(registeredUser, externalLoginInfo.RememberMe).ConfigureAwait(false);

                    return(Ok(registeredUser));
                }

                if (apptype == AppTypes.Admin)
                {
                    CoreFunc.Error(ref ErrorsList, "You do not have permission to login here. Please contact administrator.");
                    return(Unauthorized(ErrorsList));
                }
                /// check if the user is registered using other methods
                User user = await _UserManager
                            .FindByEmailAsync(externalLoginUser?.Email).ConfigureAwait(false);

                if (user != null)
                {
                    RegistrationMethod registrationMethod = await _DbContext.RegistrationMethods
                                                            .FirstOrDefaultAsync(r => r.User.Id == user.Id).ConfigureAwait(false);

                    if (registrationMethod.Type != RegistrationTypes.Application)
                    {
                        /// in the case any exceptions return the following error
                        CoreFunc.Error(ref ErrorsList, $"Please use {registrationMethod.Type} account to login.");
                    }
                    else
                    {
                        /// in the case any exceptions return the following error
                        CoreFunc.Error(ref ErrorsList, $"Please use Email and Password to login");
                    }
                    return(StatusCode(403, ErrorsList));
                }

                externalLoginUser.Role = await _DbContext.Roles.FirstOrDefaultAsync(r => r.Name == "Customer").ConfigureAwait(false);

                // else if the user is not registered but information is received from external login
                externalLoginUser.Id = -1;
                return(StatusCode(206, externalLoginUser));
            }
            catch (Exception ex)
            {
                CoreFunc.Error(ref ErrorsList, _LoggingService.LogException(Request.Path, ex, User));
                return(StatusCode(417, ErrorsList));
            }
        }