Bypass 2FA with Playwright .NET

playwright with 2fa

Playwright is a tool for end-to-end (e2e) browser testing. Most business logic usually requires a logged-in user, so we need to authenticate the test user from our code programmatically.

One of the challenges of automatic login in e2e testing is 2-factor authentication or 2FA. Even though it doesn’t make much sense to have 2FA enabled for test users, being able to log in with a 2FA user can be very handy sometimes.

In this article, we explore how we can utilize an authenticated browser state and manual login to bypass 2-factor authentication in our playwright tests.

What is Playwright’s authenticated browser state?

Technically, it’s just a json file that contains a browser state - cookies and local storage. This file can be reused between test executions and, thus, cookies and local storage are also reused.

Since web app authentication is usually implemented based on cookies or tokens (stored in the local storage), we can:

How to save Playwright’s browser state to a file?

We can save a browser state either programmatically or manually. Since it is hard to programmatically log in with a 2FA user, we are going to do it manually.

The following command opens the browser and, once the window is closed, the browser cookies and local storage data will be written to auth.json:

pwsh playwright.ps1 open --save-storage=auth.json

Execute this command from the folder where playwright.ps1 is located. For me, it’s bin/Debug/net7.0/, but your path can slightly differ depending on the .NET version you are using. Make sure you have built your project, you won’t be able to find playwright.ps1 otherwise since it’s generated during the first build for Playwright .NET.

Once a new browser window is opened, log in with your user and close the browser. At this point, you should have the auth.json file generated, open it and validate that the local storage and cookies are indeed saved.

How to use a browser state file in Playwright .NET tests?

We can now use the file we generated in the previous step to reuse the cookies and local storage of the logged-in user in our tests:

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new()
    Headless = false,
    SlowMo = 2000,

// Create a new context with the saved storage state.
var context = await browser.NewContextAsync(new()
    StorageStatePath = "auth.json"

// Page will be using the context from auth.json,
// so you can write your test assuming the user is already logged in.
var page = await context.NewPageAsync();

await page.GotoAsync("");


comments powered by Disqus