selenium passkeys testing nodejsWebAuthn Know-How

Selenium Passkeys E2E Testing in Node.js

This tutorial explains how to use Selenium for automated E2E testing of passkey solutions in Node.js

Blog-Post-Author

Amine

Created: September 13, 2024

Updated: October 1, 2024


Our mission is to make the Internet a safer place, and the new login standard passkeys provides a superior solution to achieve that. That's why we want to help you understand passkeys and its characteristics better.

1. Introduction#

The most secure and most convenient passwordless authentication method are passkeys which are gaining prominence. While they bring a lot of benefits, they also present testing challenges due to their reliance on physical authenticators (e.g. Face ID, Touch ID, Windows Hello). Thankfully, Selenium's Virtual Authenticator enables developers to automate passkey flow testing without physical devices.

This blog post will guide you by answering some related questions:

  • What is Selenium WebDriver, and how does it facilitate end-to-end (E2E) testing in Node.js applications?
  • How can Selenium WebDriver simulate WebAuthn interactions, such as registering and authenticating a passkey?
  • What are virtual authenticators, and how can they be configured in Selenium for WebAuthn testing?
  • What are the key steps to install and configure Selenium WebDriver in a Node.js environment?
  • How do you capture and validate the passkey authentication process within a Selenium test?
  • What are the potential challenges and limitations of using Selenium WebDriver for WebAuthn testing, and how can some of them be mitigated?

2. Background Information to Get Started#

In the following, you find some relevant background information to get you started.

2.1 Why Automate Passkey Testing?#

WebAuthn-based passkeys are essential for building secure and convenient authentication flows. Testing them manually, however, can be time-consuming and error-prone, especially with different devices and user flows. Automating these tests ensures that your application works seamlessly under various scenarios, including:

  • Passkey creation and registration
  • Successful login using passkeys
  • Handling passkey authentication failures

With Selenium WebDriver, you can simulate these flows using a Virtual Authenticator, allowing for robust test automation across your web app.

Substack Icon

Subscribe to our Passkeys Substack for the latest news, insights and strategies.

Subscribe

2.2 Why Choose Selenium for Passkey Testing?#

Selenium is a powerful choice for automating passkey authentication testing due to several key advantages:

  • Cross-browser support: Works seamlessly across Chrome, Firefox, Safari, and Edge.
  • Virtual Authenticator: Simulate WebAuthn flows like passkey creation and login without physical devices.
  • Extensive ecosystem: Widely adopted with strong community support and integrations like Mocha.
  • Proven reliability: Trusted by major enterprises like IBM and EY for large-scale, complex testing needs (source).

2.2.1 Minimum Browser Versions#

To ensure full compatibility for passkey testing, the following minimum browser versions are required for Selenium 4:

  • Chrome: Version 75+ [source].
  • Firefox: Version 78+ [source].
  • Safari: Safari: For Safari versions 10 and above, SafariDriver comes bundled by default with the browser preinstalled in macOS. Earlier versions required the Safari WebDriver extension, which is no longer supported for testing. [source]
  • Edge: Version 79+ [source].

Selenium 3: While it's technically possible to use passkeys in Selenium 3, the lack of native support requires numerous workarounds and unconventional methods. A demonstration of this approach can be seen in this Youtube Video

2.2.2 Why Mocha?#

Mocha is a JavaScript test framework known for running tests asynchronously. It supports both synchronous and asynchronous code, providing a flexible structure for test suites, making it a solid choice for Selenium-based end-to-end testing.

Overall, Selenium’s flexibility and reliability make it ideal for robust passkey testing across different platforms and scenarios.

2.3 How Does Selenium’s Virtual Authenticator Work?#

The Virtual Authenticator in Selenium allows you to simulate roaming authenticators like hardware security keys ( e.g. YubiKeys) or built-in platform authenticators (e.g., Touch ID, Face ID) when testing WebAuthn flows. This feature is crucial for automating passkey registration and login processes without needing real physical devices.

Key aspects of the Virtual Authenticator:

  • Simulates hardware: Mimics physical authenticators such as hardware security keys or platform authenticators.
  • Supports CTAP2: Uses the CTAP2 protocol, which is required for modern WebAuthn interactions.
  • Customizable user verification: You can configure whether User Verification (to validate the user is not only present, but also the right user is verified) is successful or fails, to test different scenarios.
  • Resident key support: Simulates resident keys (discoverable credentials), which store credentials on the device.

How the Virtual Authenticator Handles Passkey / WebAuthn Challenges

The Virtual Authenticator in Selenium directly intercepts passkey authentication / WebAuthn challenges during testing. When a web application sends a challenge as part of a WebAuthn request, the virtual authenticator captures it, signs it with its configured private key, and returns the signed response to the application. This process mimics a real physical authenticator's handling of such challenges.

3. Implementation#

3.1 Prerequisites#

Before we dive into setting up the tests, ensure that you have the following tools and knowledge:

  1. Node.js and npm installed. Install Node.js from the official website.
  2. Familiarity with Node.js and Selenium WebDriver.
  3. Basic knowledge of WebAuthn and passkey authentication.

Required Libraries and Tools

  • Selenium WebDriver: A browser automation tool to interact with web elements.
  • Mocha: A JavaScript testing framework that helps organize and run test cases. Alternatively, you can use Jest, but Mocha is recommended for Selenium-based on the documentation.

3.3 Setting Up Selenium for Passkey Testing#

Follow these steps to set up Selenium for automated passkey testing.

Step 1: Installing Selenium WebDriver#

To interact with the browser using Selenium, install the selenium-webdriver package via npm:

npm install selenium-webdriver

Step 2: Setting Up Mocha#

For structuring our tests, we’ll use Mocha. Install Mocha with:

npm install mocha

Mocha offers a flexible framework for organizing and running test suites, making it an excellent choice for Selenium-based end-to-end testing.

Slack Icon

Become part of our Passkeys Community for updates and support.

Join

Step 3: Your First Test Script#

Now, let’s create a basic test script using Mocha and Selenium WebDriver. This test will include WebAuthn interaction via a virtual authenticator.

Create a test file namedtest.spec.jsand add the following code to interact with the browser, perform basic navigation, and execute fundamental Passkey Creation and Authentication:

test.spec.js
const {Builder, By, until} = require("selenium-webdriver"); const { VirtualAuthenticatorOptions, Transport, Protocol, } = require("selenium-webdriver/lib/virtual_authenticator"); const mocha = require("mocha"); const {describe, it, before} = mocha; describe("Passkey Authentication Tests", function () { this.timeout(10000); const timeOut = 5000; let driver; before(async function () { driver = await new Builder().forBrowser("chrome").build(); // Set up the virtual authenticator with the desired options let options = new VirtualAuthenticatorOptions(); options.setProtocol(Protocol.CTAP2); options.setTransport(Transport.INTERNAL); options.setHasUserVerification(true); options.setIsUserVerified(true); options.setHasResidentKey(true); // Add the virtual authenticator to the WebDriver await driver.addVirtualAuthenticator(options); }); it("should load the login page", async function () { await driver.get("https://passkeys.eu"); const emailField = await driver.wait( until.elementLocated(By.id("email")), timeOut ); await emailField.sendKeys(`test+${Date.now()}@test.com`); await emailField.submit(); await driver.wait( until.elementLocated(By.className("cb-passkey-list-container")), timeOut ); }); });

Run the test using Mocha:

npx mocha test.spec.js
Demo Icon

Want to try passkeys yourself? Check our Passkeys Demo.

Try Passkeys

The test opens a Chrome browser window and automatically navigates to https://passkeys.eu

selenium webauthn test

It then types in a randomized email and submits it

selenium passkey creation test

This will trigger the passkey challenge, which the virtual authenticator will handle automatically.

selenium webauthn registration test

Finally, you're successfully logged in and can view the newly created passkey.

selenium passkey list test

To maximize the potential of Selenium WebDriver for simulating user actions and detecting DOM changes, explore their documentation thoroughly. Focus on these crucial areas:

Moreover, dive into Mocha's Getting Started guide. Pay close attention to these essential concepts:

3.4 Configuring Virtual Authenticator for Passkey Testing#

We now teach how to configure the Virtual Authenticator in Selenium WebDriver to simulates authenticators.

Setting Up the Virtual Authenticator

The following code demonstrates how to configure a virtual authenticator for passkey testing. This example will simulate the CTAP2 protocol with internal device transport.

  1. Initialize Virtual Authenticator Options:

    const { VirtualAuthenticatorOptions, Protocol, Transport } = require('selenium-webdriver/lib/virtual_authenticator'); let options = new VirtualAuthenticatorOptions(); options.setProtocol(Protocol['CTAP2']); // CTAP2 for passkey authentication options.setTransport(Transport['INTERNAL']); // INTERNAL transport for built-in authenticators options.setHasUserVerification(true); // Supports user verification options.setIsUserVerified(true); // User is verified options.setHasResidentKey(true); // Supports resident keys
    • setProtocol(Protocol['CTAP2']): Configures the virtual authenticator to use the CTAP2 protocol, which is necessary for passkey operations.
    • setTransport(Transport['INTERNAL']): Simulates an authenticator built into the platform, such as a mobile device or laptop.
    • setHasUserVerification(true): Indicates that the authenticator can verify the user's identity, essential for secure authentication processes.
    • setIsUserVerified(true): Simulates a scenario where the user has already been verified by the authenticator. when set to false it mimics an authentication failure, such as when a user cancels the passkey input. Note that this setting is effective only when setHasUserVerification is true.
    • setHasResidentKey(true): Enables the virtual authenticator to support resident keys, which are credentials stored directly on the device (contrary to non-resident keys).

    These options help you simulate a complete passkey authentication scenario in a test environment, ensuring that your application handles these flows correctly.

  2. Add the Virtual Authenticator to the WebDriver:

    await driver.addVirtualAuthenticator(options);

This setup will simulate a passkey scenario where the user is verified and resident keys are supported. You can add this authenticator to your Selenium WebDriver to test passkey authentication.

If you are using a version of Selenium WebDriver earlier than 4.3.0, you will need to upgrade to at least this version to access the Virtual Authenticator feature and ensure your tests can fully simulate passkey authentication scenarios (Release Notes).

3.5 Using Virtual Authenticator for Passkey Testing#

3.5.1 Testing Passkey Registration#

Passkey registration is the first step in a passkey authentication flow. The following test simulates user interaction during the registration process and verifies that the passkey is successfully created.

it('should successfully register a passkey', async function () { await driver.get('https://yourapp.com/register'); // Change the URL to your registration URL const registerButton = await driver.findElement(By.id('registerPasskeyButton')); // Change this to find the passkey append trigger await registerButton.click(); // Simulate passkey registration const successMessage = await driver.wait( until.elementLocated(By.xpath("//*[contains(text(),'Passkey successfully registered')]")), 5000 ); // Change the locator to your success indicator in the HTML assert.strictEqual(await successMessage.isDisplayed(), true); });
Debugger Icon

Want to experiment with passkey flows? Try our Passkeys Debugger.

Try for Free

3.5.2 Testing Passkey Login#

Once registered, a user should be able to log in using their passkey. Here’s a test case for validating the passkey login flow:

it('should log in with passkey', async function () { await driver.get('https://yourapp.com/login'); // Change the URL to your login URL const loginButton = await driver.findElement(By.id('loginWithPasskeyButton')); // change this to your passkey login trigger await loginButton.click(); // Simulate passkey authentication const loggedInText = await driver.wait( until.elementLocated(By.xpath("//*[contains(text(),'Welcome, you are logged in')]")), // Change this to locate your login success indicator 5000 ); assert.strictEqual(await loggedInText.isDisplayed(), true); });

3.6 Simulating Authentication Failures#

WebAuthn interactions may fail for various reasons, such as incorrect user verification or unsupported devices. You can simulate these failures in your tests and ensure that your application handles them correctly.

Simulating User Verification Failure

In this example, we simulate a scenario where the user verification fails during passkey login:

it('should handle failed passkey authentication', async function () { await driver.get('https://yourapp.com/login'); await driver.setUserVerified(false); // Simulate failed [user verification](/blog/webauthn-user-verification) const loginButton = await driver.findElement(By.id('loginWithPasskeyButton')); await loginButton.click(); const failureMessage = await driver.wait( until.elementLocated(By.xpath("//*[contains(text(),'Passkey authentication failed')]")), 5000 ); assert.strictEqual(await failureMessage.isDisplayed(), true); });

3.7 Handling Network Issues in Testing#

Network issues, such as timeouts, can disrupt passkey authentication flows. Although the WebDriver doesn't allow for direct network simulation, you can simulate network failures in your tests by altering the API endpoint or manipulating localStorage data in the browser (if your application stores such data there).

Ben Gould Testimonial

Ben Gould

Head of Engineering

I’ve built hundreds of integrations in my time, including quite a few with identity providers and I’ve never been so impressed with a developer experience as I have been with Corbado.

10,000+ devs trust Corbado & make the Internet safer with passkeys. Got questions? We’ve written 150+ blog posts on passkeys.

Join Passkeys Community

Simulating a Network Timeout

Here’s an example of how to simulate a network timeout by changing the API URL stored in the browser’s local storage:

await driver.executeScript(` window.localStorage.setItem('apiUrl', 'https://fake-endpoint.com'); `);

This method allows you to test how your app handles network-related issues during authentication processes.

4. Conclusion#

Selenium WebDriver's Virtual Authenticator provides a robust tool for automating passkey-related authentication flows in web applications. By simulating various scenarios - including successful registration, login, and authentication failures - developers can ensure their applications are resilient and handle most WebAuthn interactions correctly.

4.1 What We Can Test with Selenium:#

  • Triggering passkey registration and login flows
  • Simulating successful passkey authentication using a virtual authenticator (Passkey Button, Conditional UI, Identifier-Based)
  • Handling passkey login failures (e.g., user verification failure)
  • Passkey listing, appending, and deletion
  • Simulating network issues and verifying application response (e.g., timeouts)

4.2 What We Cannot Test with Selenium:#

  • Real hardware interactions (e.g., actual biometrics, security keys) due to Selenium's limitations
  • Browser-native dialogs and permission prompts triggered by WebAuthn, such as "Use Face ID" prompts

The next step is to integrate these tests into your CI/CD pipeline, enabling continuous validation of your passkey authentication processes.

Share this article


LinkedInTwitterFacebook

Enjoyed this read?

🤝 Join our Passkeys Community

Share passkeys implementation tips and get support to free the world from passwords.

🚀 Subscribe to Substack

Get the latest news, strategies, and insights about passkeys sent straight to your inbox.


We provide UI components, SDKs and guides to help you add passkeys to your app in <1 hour

Start for free