public Authentication()
        {
            // Get access token
            GetAccessTokenCommand = new[]
            {
                ApplicationId.Select(v => !string.IsNullOrWhiteSpace(v)),
                ApplicationSecret.Select(v => !string.IsNullOrWhiteSpace(v)),
                RedirectUrl.Select(v => !string.IsNullOrWhiteSpace(v)),
                EmailAddress.Select(v => !string.IsNullOrWhiteSpace(v)),
            }
            .CombineLatestValuesAreAllTrue()
            .ToReactiveCommand(false)
            .AddTo(Disposable);

            // Refresh access token
            RefreshAccessTokenCommand = new[]
            {
                AccessToken.Select(v => !string.IsNullOrWhiteSpace(v)),
                RefreshToken.Select(v => !string.IsNullOrWhiteSpace(v)),
            }
            .CombineLatestValuesAreAllTrue()
            .ToReactiveCommand(false)
            .AddTo(Disposable);

            // Revoke access token
            RevokeAccessTokenCommand = new[]
            {
                AccessToken.Select(v => !string.IsNullOrWhiteSpace(v)),
                RefreshToken.Select(v => !string.IsNullOrWhiteSpace(v)),
            }
            .CombineLatestValuesAreAllTrue()
            .ToReactiveCommand(false)
            .AddTo(Disposable);
        }
        /// <summary>
        /// Save values from basic settings page
        /// </summary>
        public void Save(Guid id)
        {
            using (var context = GigyaContext.Get())
            {
                // get settings to update
                var settings = context.Settings.FirstOrDefault(i => i.SiteId == id) ?? new GigyaSitefinityModuleSettings {
                    SiteId = id
                };

                // update all fields
                settings.ApiKey           = this.ApiKey.Trim();
                settings.DebugMode        = this.DebugMode;
                settings.ApplicationKey   = this.ApplicationKey.Trim();
                settings.DataCenter       = !string.IsNullOrEmpty(this.DataCenter) ? this.DataCenter : this.DataCenterOther;
                settings.EnableRaas       = this.EnableRaas;
                settings.GlobalParameters = this.GlobalParameters;
                settings.Language         = !string.IsNullOrEmpty(this.Language) ? this.Language : this.LanguageOther;
                settings.LanguageFallback = this.LanguageFallback;
                settings.MappingFields    = this.MappingFields;
                settings.RedirectUrl      = this.RedirectUrl;
                settings.LogoutUrl        = this.LogoutUrl;
                settings.SessionTimeout   = this.SessionTimeout;
                settings.SessionProvider  = this.SessionProvider;
                settings.GigyaSessionMode = this.GigyaSessionMode;

                if (settings.SessionProvider == GigyaSessionProvider.Gigya)
                {
                    switch (settings.GigyaSessionMode)
                    {
                    case GigyaSessionMode.Session:
                        settings.SessionTimeout = 0;
                        break;

                    case GigyaSessionMode.Forever:
                        settings.SessionTimeout = -2;
                        break;
                    }
                }

                var mappingFields = JsonConvert.DeserializeObject <List <MappingField> >(MappingFields);
                if (mappingFields == null || !mappingFields.Any())
                {
                    throw new ArgumentException(Constants.Errors.UIDFieldRequired);
                }

                // validate that there is a mapping field for UID
                var usernameMappingExists = mappingFields.Any(i => i.GigyaFieldName == Constants.GigyaFields.UserId);
                if (!usernameMappingExists)
                {
                    throw new ArgumentException(Constants.Errors.UIDFieldRequired);
                }

                if (mappingFields.Any(i => string.IsNullOrEmpty(i.GigyaFieldName)))
                {
                    throw new ArgumentException(Constants.Errors.GigyaFieldNameRequired);
                }

                if (mappingFields.Any(i => string.IsNullOrEmpty(i.CmsFieldName)))
                {
                    throw new ArgumentException(Constants.Errors.CmsFieldNameRequired);
                }

                // application secret that we will use to validate the settings - store this in a separate var as it's unencrypted
                string plainTextApplicationSecret = string.Empty;

                // check if user can view application secret
                if (!string.IsNullOrEmpty(ApplicationSecret))
                {
                    plainTextApplicationSecret = ApplicationSecret.Trim();
                    var identity = ClaimsManager.GetCurrentIdentity();
                    var canViewApplicationSecret = identity.IsAuthenticated && Gigya.Module.Connector.Admin.Roles.HasRole(identity);
                    if (canViewApplicationSecret)
                    {
                        if (!Encryptor.IsConfigured)
                        {
                            throw new ArgumentException("Encryption key not specified. Refer to installation guide.");
                        }

                        settings.ApplicationSecret = Encryptor.Encrypt(plainTextApplicationSecret);
                    }
                }

                if (string.IsNullOrEmpty(plainTextApplicationSecret) && Encryptor.IsConfigured && !string.IsNullOrEmpty(settings.ApplicationSecret))
                {
                    plainTextApplicationSecret = TryDecryptApplicationSecret(settings.ApplicationSecret);
                }

                var mappedSettings = Map(settings);

                // validate input
                SettingsHelper.Validate(mappedSettings);

                // verify settings are correct
                var apiHelper    = new GigyaApiHelper(SettingsHelper, Logger);
                var testResponse = apiHelper.VerifySettings(mappedSettings, plainTextApplicationSecret);
                if (testResponse.GetErrorCode() != 0)
                {
                    var gigyaErrorDetail = testResponse.GetString("errorDetails", string.Empty);
                    var message          = string.Concat("Error: ", testResponse.GetErrorMessage());
                    if (!string.IsNullOrEmpty(gigyaErrorDetail))
                    {
                        message = string.Concat(message, ". ", gigyaErrorDetail);
                    }

                    throw new InvalidOperationException(message);
                }

                context.Add(settings);
                context.SaveChanges();
            }
        }