UI Automation Testing – Basic Authentication using Selenium and Playwright

Joe Blogs

The codebase for this post can be found here

When creating UI automation tests for web applications, one of the more complicated scenarios to solve is authentication, especially when working in an enterprise environment where requirements such as Multi-Factor Authentication can often be enforced.

This blog post is going to cover how to use both Selenium and Playwright to automate authentication when using Azure AD as your identity management system, with an account that has been configured to use basic authentication with MFA disabled.

The steps this post covers are:

  1. Navigating to your application where your login button resides
  2. Clicking the log in button to redirect to the Azure AD screen where your username can be inserted
  3. Entering your username in the Azure AD screen that appears
  4. Clicking next
  5. Authenticating the user and redirecting back to your application

Selenium

The code for the Selenium example can be found within the src/Selenium directory on GitHub here. Once you have cloned the code, run the project by navigating to the src/Selenium/SeleniumAzureAdBasicAuth directory and typing the following command:

dotnet run "replace_with_username" "replace_with_password" "replace_with_auth_company_domain e.g. access.domain.com" "replace_with_your_application_url_where_your_login_button_resides" "replace_with_id_of_your_login_button"

This should open a Chrome browser and perform the 5 steps mentioned above.

The code for the steps run when using Selenium can be found in the AzyreAdBasicAuthSteps.cs class. Getting to the screen before the authentication pop-up in the browser is all trivial and well documented code when using Selenium. The part that will be of interest is the code in the method AzureAdRedirectWithAuthDetails shown in the snippet below:

public static IWebDriver AzureAdRedirectWithAuthDetails(this IWebDriver driver, string userName, string password, string domainToReplace)
{
Thread.Sleep(TimeSpan.FromSeconds(5));
var newUrlWithUserCredentials = driver.Url.Replace(domainToReplace, $"{WebUtility.HtmlEncode(userName)}:{password}@{domainToReplace}");
driver.Navigate().GoToUrl(newUrlWithUserCredentials);
return driver;
}

The first thing this code does is sleep for 5 seconds (there might be a better way to do this as I am not a Selenium expert), this is to allow the browser time to redirect to the screen that will show the username and password dialog. Line 4 then takes the URL from the browser, which is a redirect to Azure AD, appends the username and password to it and then navigates to the newly formed URL. Azure AD then takes this information, authenticates the user, and navigates the user to the redirect URL setup within app registration.

Playwright

The code for the Playwright example can be found within the src/Playwright directory on GitHub here. Once you have cloned the code, run the project by navigating to the src/Playwright/PlaywrightAzureAdBasicAuth directory and typing the following command:

dotnet run "replace_with_username" "replace_with_password" "replace_with_your_application_url_where_your_login_button_resides" "replace_with_id_of_your_login_button"

Similarly to the Selenium project, the code for getting to the login screen for Azure AD to insert your username is all standard code. However, the difference between Playwright and Selenium is that you do not need to pass the username and password into the URL to authenticate. As shown in the code below (lines 21-25) from the Program.cs, the username and password can be set against the HttpCredentials when launching the browser

using Cocona;
using Microsoft.Playwright;
using PlaywightAzureAdBasicAuth;
var builder = CoconaApp.CreateBuilder();
var app = builder.Build();
app.AddCommand(async ([Argument(Description = "Username to login with")] string userName,
[Argument(Description = "Password to login with")] string password,
[Argument(Description = "The url of your application as a starting point where your login button is located")] string applicationUrl,
[Argument(Description = "The html id of your login button")] string loginButtonId) =>
{
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchPersistentContextAsync("", new BrowserTypeLaunchPersistentContextOptions()
{
Headless = false,
Args = new List<string>
{
"-incognito"
},
HttpCredentials = new HttpCredentials
{
Username = userName,
Password = password
}
});
var page = browser.Pages.First();
await page.GoToApplicationAsync(applicationUrl);
await page.ClickLogonAsync(loginButtonId);
await page.SetAzureAdLoginDetailsAsync(userName);
Console.ReadLine();
});
app.Run();

Conclusion

Overall I found Playwright to be a more elegant solution when implementing a solution for basic authentication when using Azure AD. The approach for setting the credentials to be used is much cleaner (there could be a better way in Selenium I do not know about), and the fact that you don’t need to add code in to wait for elements to load/appear is far superior.

If anyone has any comments on the above, or tips on how the two solutions can be improved, please reach out to me on LinkedIn as I am keen to learn more!