Dear Support,
I have an app (angular+.NET core) working with per tenant settings of social logins and I have a couple of questions.
We see that with disconnect button we don't disconnect from the social. E.g. with Azure AD we don't signout and the second time we try to login we login without credentials request. How can we solve this issue?
Is there the possibility to inhibit the local login only for the users that has a social login enabled?
Thank you in advance for you support
1 Answer(s)
-
0
Hi @niengineering
This behavior is expected and by design.
In ASP.NET Zero, the Disconnect button only removes the association between the local user and the external login provider from the database (the
UserLoginstable). It does not terminate the session on the external identity provider (Azure AD, Google, Facebook, etc.).This aligns with standard OAuth 2.0 / OpenID Connect behavior.
- External providers (Azure AD, Google, Facebook) manage their own sessions
- Disconnect only deletes the local user provider mapping
- The provider’s authentication cookie remains active in the browser
- On the next login attempt, the provider silently re authenticates the user
Explicit External Provider Logout
You can extend the logout flow to redirect users to the provider’s logout endpoint.
Example
*.Web.Core:public async Task<IActionResult> ExternalLogout(string providerName) { await _signInManager.SignOutAsync(); var logoutUrl = providerName switch { "Microsoft" => $"https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri={_appConfiguration["App:ClientRootAddress"]}", "Google" => $"https://accounts.google.com/Logout?continue={_appConfiguration["App:ClientRootAddress"]}", _ => Url.Action("Login") }; return Redirect(logoutUrl); }This ensures the external provider session is also terminated.
Force Account Selection (Azure AD)
If full logout is not desired, you can force Azure AD to always prompt the user to select an account:
options.Events.OnRedirectToIdentityProvider = context => { context.ProtocolMessage.SetParameter("prompt", "select_account"); return Task.CompletedTask; };This prevents silent re login using an existing Azure AD session.
Extend Disconnect Logic on the Angular Side
After unlinking the social login, you can open the provider’s logout URL in a new tab:
disconnectFromSocialProvider(providerName: string): void { this._userLinkService.unlinkUser( new UnlinkUserInput({ providerName }) ).subscribe(() => { const logoutUrls = { 'Microsoft': 'https://login.microsoftonline.com/common/oauth2/v2.0/logout', 'Google': 'https://accounts.google.com/Logout' }; if (logoutUrls[providerName]) { window.open(logoutUrls[providerName], '_blank'); } this.notify.success(this.l('SuccessfullyDisconnected')); this.getUserLoginAttempts(); }); }Disabling Local Login for Users with Social Login Enabled
ASP.NET Zero does not provide this feature out of the box, but it can be implemented with a small customization.
Customize Authentication Logic
Extend
TokenAuthControllerorAccountAppService:public async Task<AuthenticateResultModel> Authenticate(AuthenticateModel model) { var user = await _userManager.FindByNameOrEmailAsync(model.UserNameOrEmailAddress); if (user != null) { var externalLogins = await _userManager.GetLoginsAsync(user); if (externalLogins.Any()) { throw new UserFriendlyException( L("UserHasSocialLoginEnabled", string.Join(", ", externalLogins.Select(x => x.LoginProvider))) ); } } return await base.Authenticate(model); }(Optional) Tenant Level Setting
If you want this behavior to be configurable per tenant:
public const string DisableLocalLoginForSocialUsers = "App.UserManagement.DisableLocalLoginForSocialUsers"; context.Create( DisableLocalLoginForSocialUsers, "false", scopes: SettingScopes.Tenant, isInherited: false );Usage:
var disableLocalLogin = await SettingManager.GetSettingValueAsync<bool>( AppSettings.UserManagement.DisableLocalLoginForSocialUsers); if (disableLocalLogin && externalLogins.Any()) { throw new UserFriendlyException("..."); }Angular UI
authenticate(): void { this._tokenAuthService.authenticate(this.loginModel) .pipe(finalize(() => this.saving = false)) .subscribe({ next: () => { /* success */ }, error: (error) => { if (error.error?.message?.includes('UserHasSocialLoginEnabled')) { this.message.warn(error.error.message); } else { this.message.error(error.error.message); } } }); }If you have further questions, feel free to ask. Thank you
Markdown is supportedCopy & paste or drag & drop images (max 30 MB per image)