Skip to main content
All docs
V23.2
.NET 6.0+

Active Directory and OAuth2 Authentication Providers in WinForms Applications

  • 8 minutes to read

Windows Authentication

Windows Active Directory authentication uses the current Windows account to authenticate a user in an XAF application. You can use Active Directory authentication in one of the following two configurations:

  • As the only authentication mode.
  • Together with password-based authentication.

Create a New Application with Windows Authentication

To create an application with Active Directory authentication, run the XAF Solution Wizard, proceed to the Authentication page and specify one of the following configurations:

  • To only use Active Directory authentication, select Active Directory (uses Windows account).

    Solution Wizard - Active Directory Authentication

  • To use Active Directory authentication as well as password-based authentication, select Standard (requests login and password) and enable the following option: Windows Active Directory.

    Solution Wizard - Standard and Active Directory Authentication

After that, proceed to complete the wizard.

Add Windows Authentication to an Existing Application

To enable Active Directory authentication, add the following code snippet to the application’s Startup.cs:

File: MySolution.Win/Startup.cs

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.ApplicationBuilder;
using DevExpress.ExpressApp.Win.ApplicationBuilder;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Win;
// ...
public class ApplicationBuilder : IDesignTimeApplicationFactory {
    public static WinApplication BuildApplication(string connectionString) {
        var builder = WinApplication.CreateBuilder();
        // ...
        builder.Security
            .UseIntegratedMode(options => {
                // ...
            })
            .UseWindowsAuthentication(options => {
                options.CreateUserAutomatically();
            });
        // ...
    };
}

To use both Active Directory authentication and password-based authentication, use the following code sample:

File: MySolution.Win/Startup.cs

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.ApplicationBuilder;
using DevExpress.ExpressApp.Win.ApplicationBuilder;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Win;
// ...
public class ApplicationBuilder : IDesignTimeApplicationFactory {
    public static WinApplication BuildApplication(string connectionString) {
        var builder = WinApplication.CreateBuilder();
        // ...
        builder.Security
            .UseIntegratedMode(options => {
                // ...
            })
            .UsePasswordAuthentication()
            .UseWindowsAuthentication(options => {
                options.CreateUserAutomatically();
            });
            // ... 
    };
    // ...
}; 

OAuth 2 Authentication

XAF supports Microsoft Entra ID (formerly known as Azure Active Directory) as an authentication method based on OAuth 2. You can also implement a custom OAuth 2 authentication provider to use other third-party authentication methods (Google, GitHub, Facebook, and so on).

Create a New Application with OAuth 2 Authentication (Entra ID)

To create an application with OAuth 2 authentication, run the XAF Solution Wizard, proceed to the Authentication page, select Standard (requests login and password) and enable the following option: OAuth2 Authentication Providers.

Solution Wizard - Entra ID Authentication

Proceed to complete the wizard.

After the application is created, open the application’s App.config file and specify the following options to configure Microsoft Entra ID authentication:

  • azureAD_Instance - Your Azure AD instance URL.
  • azureAD_TenantId - "common", "organizations", or a Tenant ID.
  • azureAD_ClientId - Application ID.

You can obtain values for these settings from the Azure Portal. For more information, see Desktop application authentication documentation.

Add OAuth 2 Authentication (Entra ID) to an Existing Application

To enable OAuth 2 authentication, add the following code to application’s Startup.cs. Note that password-based authentication must also be enabled:

File: MySolution.Win/Startup.cs

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.ApplicationBuilder;
using DevExpress.ExpressApp.Win.ApplicationBuilder;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Win;
// ...
public class ApplicationBuilder : IDesignTimeApplicationFactory {
    public static WinApplication BuildApplication(string connectionString) {
        var builder = WinApplication.CreateBuilder();
        // ...
        builder.Security
            .UseIntegratedMode(options => {
                // ...
            })
            .UsePasswordAuthentication()
            .UseExternalAuthentication<CustomAuthenticationProvider>()
                .AddAzureAD(opt => {
                    opt.ClientId = ConfigurationManager.AppSettings["azureAD_ClientId"];
                    opt.TenantId = ConfigurationManager.AppSettings["azureAD_TenantId"];
                    opt.Instance = ConfigurationManager.AppSettings["azureAD_Instance"];
                });
            // ... 
    };
    // ...
}; 

Add the options required to use Entra ID authentication to the App.config file:

File: MySolution.Win/App.config

<?xml version="1.0"?>
<configuration>
  <appSettings>
  <!-- fill the following settings from Azure portal https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-create-new-tenant -->
  <add key="azureAD_Instance" value="https://login.microsoftonline.com/" />
  <!-- Enter 'common', or 'organizations' or the Tenant Id obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), for example, da41245a5-11b3-996c-00a8-4d99re19f292 -->
  <add key="azureAD_TenantId" value="organizations" />
  <!-- Enter the Client Id (application ID obtained from the Azure portal), for example, ba74781c-53c2-442a-97c2-3d60de42f403 -->
  <add key="azureAD_ClientId" value="[Configure ClientId in App.config before use.]" />
  </appSettings>
</configuration>

Add a CustomAuthenticationProvider class that implements the IAuthenticationProviderV2 to the WinForms application project. You can use the following code as a reference implementation of this class (XAF Solution Wizard generates equivalent code):

public class CustomAuthenticationProvider : IAuthenticationProviderV2 {
    private readonly UserManager userManager;

    public CustomAuthenticationProvider(UserManager userManager) {
        this.userManager = userManager;
    }

    public object Authenticate(IObjectSpace objectSpace) {
        // When a user successfully logs in with an OAuth provider, you can get their unique user key.
        // The following code snippet finds an ApplicationUser object associated with this key.
        // This code also creates a new ApplicationUser object for this key automatically.
        var currentPrincipal = userManager.GetCurrentPrincipal();
        if(currentPrincipal?.Identity?.IsAuthenticated ?? false) {
            var user = userManager.FindUserByPrincipal<ApplicationUser>(objectSpace, currentPrincipal);
            if(user != null) {
                return new UserResult(user);
            }
        // The following code sample creates users for testing purposes only.
#if !RELEASE
            bool autoCreateUser = true;
            if(autoCreateUser) {
                var userResult = userManager.CreateUser<ApplicationUser>(objectSpace, currentPrincipal, user => {
                    user.Roles.Add(objectSpace.FirstOrDefault<PermissionPolicyRole>(role => role.Name == "Default"));
                });
                if(!userResult.Succeeded) {
                    // throw userResult.Error;
                }
                return userResult;
            }
#endif
        }

        return null;
    }
}

Implement a Custom OAuth 2 Authentication Provider (Google, GitHub, Facebook)

XAF includes API that allows you to extend your application with popular third-party authentication methods (Google, GitHub, Facebook, and so on). Follow the steps below to implement a custom external authentication provider and use it in a WinForms application.

First, create a class that implements the IAuthenticationHandler interface:

class CustomAuthenticationHandler : IAuthenticationHandler {
    public Task<ClaimsPrincipal> Logon(ActionBase initiator) {
        var result = new ClaimsPrincipal();
        // ...
        // Here, implement logic used to display authentication UI.
        // On successful authentication, create a ClaimsPrincipal object
        // that contains an authenticated user's information. 
        return Task.FromResult(result);
    }
    public Task Logoff() {
        // ...
        // Here, implement logic that sends a log off command
        // to an external authentication provider
        // or invalidates the authentication token.
        return Task.CompletedTask;
    }
} 

Implement an extension method that registers the new authentication scheme and required services:

public static class CustomAuthenticationExtensions {
    public static WinExternalAuthenticationBuilder AddCustomAuthentication(this WinExternalAuthenticationBuilder externalWinAuthenticationBuilder) {
        IServiceCollection services = externalWinAuthenticationBuilder.Context.Services;
        services.AddSingleton<CustomAuthenticationHandler>();
        services.AddSingleton((IAuthenticationScheme)new AuthenticationScheme(
            "CustomAuthenticstionScheme", "Custom Authentication", typeof(CustomAuthenticationHandler)));
        return externalWinAuthenticationBuilder;
    }
}

The above-mentioned code sample specifies the following settings:

  • “CustomAuthenticationScheme” - The new authentication scheme’s unique name. We recommend that you use a name similar to the name of the used authentication provider (Google, GitHub, Facebook, and so on).
  • “Custom Authentication” - The authentication scheme’s name to display on the Login form.

In the WinForms application project, add a CustomAuthenticationProvider class that implements the IAuthenticationProviderV2 interface. In this class, implement authorization logic that involves the ClaimsPrincipal produced by your IAuthenticationHandler implementation. For example, you can authenticate the user on the application side based on data queried from an Object Space; or create a new user record if the user was not found. You can use the following code as a reference implementation of the CustomAuthenticationProvider class:

public class CustomAuthenticationProvider : IAuthenticationProviderV2 {
    private readonly UserManager userManager;

    public CustomAuthenticationProvider(UserManager userManager) {
        this.userManager = userManager;
    }

    public object Authenticate(IObjectSpace objectSpace) {
        // When a user successfully logs in with an OAuth provider, you can get their unique user key.
        // The following code snippet finds an ApplicationUser object associated with this key.
        // This code also creates a new ApplicationUser object for this key automatically.
        var currentPrincipal = userManager.GetCurrentPrincipal();
        if(currentPrincipal?.Identity?.IsAuthenticated ?? false) {
            var user = userManager.FindUserByPrincipal<ApplicationUser>(objectSpace, currentPrincipal);
            if(user != null) {
                return new UserResult(user);
            }
        // The following code sample creates users for testing purposes only.
#if !RELEASE
            bool autoCreateUser = true;
            if(autoCreateUser) {
                var userResult = userManager.CreateUser<ApplicationUser>(objectSpace, currentPrincipal, user => {
                    user.Roles.Add(objectSpace.FirstOrDefault<PermissionPolicyRole>(role => role.Name == "Default"));
                });
                if(!userResult.Succeeded) {
                    // throw userResult.Error;
                }
                return userResult;
            }
#endif
        }

        return null;
    }
}

To enable your custom authentication provider, add the following code snippet to application’s Startup.cs:

File: MySolution.Win/Startup.cs

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.ApplicationBuilder;
using DevExpress.ExpressApp.Win.ApplicationBuilder;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Win;
// ...
public class ApplicationBuilder : IDesignTimeApplicationFactory {
    public static WinApplication BuildApplication(string connectionString) {
        var builder = WinApplication.CreateBuilder();
        // ...
        builder.Security
            .UseIntegratedMode(options => {
                // ...
            })
            UsePasswordAuthentication() 
            .UseExternalAuthentication<CustomAuthenticationProvider>()
                .AddCustomAuthentication();
            };
        // ...
};  

After you run the application, you will see a button that initiates authentication with your custom provider on the Login form:

Login Form - Custom Authentication Action

Access External Authentication Provider Actions

When you use Entra ID and/or Active Directory authentication in conjunction with password-based authentication, corresponding action buttons are added to the Login form:

Login Form - External Authentication Provider Actions

To customize these buttons, implement a custom controller that accesses the buttons as shown below:

using DevExpress.ExpressApp.Win.SystemModule;
using DevExpress.ExpressApp;

namespace MySolution.Win.Controllers { 
    public class AdditionalLogonActionsCustomizationController : WindowController {
        protected override void OnActivated() {
            base.OnActivated();
            AdditionalLogonActionsController additionalLogonActionsController = Frame.GetController<AdditionalLogonActionsController>();
            if (additionalLogonActionsController != null) {
                var action = additionalLogonActionsController.Actions.Where(
                    action => action.Id == "EntraID"
                ).FirstOrDefault();
                if (action != null) {
                    // action.Caption = "CustomCaption";
                    // action.ImageName = "CustomImageName";
                }
            }
        }
    }
}

Override the XafApplication class’s CreateLogonWindowControllers method as shown below:

File: MySolution.Win/WinApplication.cs

public class MySolutionWindowsFormsApplication : WinApplication {
    // ...
    protected override List<Controller> CreateLogonWindowControllers() {
        var result = base.CreateLogonWindowControllers();
        result.Add(new AdditionalLogonActionsCustomizationController());
        return result;
    }
}

Localize External Authentication Action Captions

Edit the Localization->Captions->LogInWithActionCaption item in the WinForms Application Model to modify the localization value for external authentication captions (“Log In with” in en-US localization):

Model Editor - Localize External Authentication Provider Actions

The image below illustrates the result.

Login Form - Localize External Authentication Provider Actions

Limitations

  • The functionality described in this topic is only supported for WinForms applications that target .NET 6+.
  • OAuth 2 authentication is not supported in WinForms applications with Middle-Tier Security.
  • Active Directory authentication used in combination with password-based authentication is not supported in WinForms applications with Middle-Tier Security.
See Also