How to Automate SSO Login in Playwright with Okta, Auth0, or Microsoft Entra ID

Playwright can automate Single Sign-On (SSO) through identity providers such as Okta, Auth0, and Microsoft Entra ID. For a single test, you can automate the complete sign-in flow; when multiple tests use the same authenticated account, Playwright can save and reuse the authenticated browser state with storageState.

With plain Playwright, your test project owns the authentication setup, saved state files, project configuration, expiry handling, and any strategy for multiple roles or parallel users. Leapwork Play takes a different approach: record the SSO login once as a reusable LoginSSO test case and reference that login from business tests.

What is SSO in Playwright testing?

Single Sign-On allows an application to delegate authentication to an identity provider (IdP), such as:

  • Okta

  • Auth0

  • Microsoft Entra ID

A typical browser flow looks like this:

Open application → Redirect to identity provider → Sign in → Redirect back to application → Continue authenticated

For example, if an Orders page is protected by SSO, opening the application might redirect the browser to the organization's identity provider. After successful authentication, the identity provider redirects the browser back to the application.

Playwright can automate that browser flow like any other user journey.

What do you need before automating SSO?

Before you start, make sure you have:

  • A Playwright Test project that already runs.

  • The URL of the SSO-protected application.

  • A dedicated test identity approved for automation.

  • The username and password supplied through environment variables or a secret-management system.

  • An authentication policy that permits the automated flow you intend to test.

The examples below use:

  • APP_URL for the application URL.

  • SSO_USER for the test username.

  • SSO_PASSWORD for the test password.

Do not hardcode SSO credentials in the test source.

How do you automate an SSO login directly in Playwright?

For a single test, keeping the authentication steps in the test itself is a reasonable starting point.

For example:

JavaScript
import { test, expect } from '@playwright/test';

test('user can view orders', async ({ page }) => {
  await page.goto(process.env.APP_URL!);

  await page
    .getByLabel('Email')
    .fill(process.env.SSO_USER!);

  await page
    .getByRole('button', { name: 'Next' })
    .click();

  await page
    .getByLabel('Password')
    .fill(process.env.SSO_PASSWORD!);

  await page
    .getByRole('button', { name: 'Sign in' })
    .click();

  await page.waitForURL(`${process.env.APP_URL}/**`);

  await page.goto(`${process.env.APP_URL}/orders`);

  await expect(
    page.getByRole('heading', { name: 'Orders' })
  ).toBeVisible();
});

Replace the sample labels and button names with the controls exposed by your own identity provider.

The important flow is:

  1. Open the protected application.

  2. Follow the redirect to the identity provider.

  3. Enter the approved test credentials.

  4. Complete the sign-in flow.

  5. Wait until the browser has returned to a clearly authenticated application state.

  6. Continue with the business test.

How should you handle SSO credentials?

Keep authentication credentials out of the test source.

For example:

await page
  .getByLabel('Email')
  .fill(process.env.SSO_USER!);

await page
  .getByLabel('Password')
  .fill(process.env.SSO_PASSWORD!);

Supply those values through environment variables or an appropriate secret-management system.

If you use a local .env file during development, keep it out of source control and restrict access to it.

Also avoid writing passwords, tokens, authentication responses, or other sensitive values to test logs.

Why shouldn't every Playwright test perform the complete SSO login?

If every test contains the complete login flow, every test has to authenticate through the identity provider again.

That introduces:

  • repeated redirects

  • repeated authentication requests

  • duplicated login code

  • additional dependency on the identity provider throughout the suite

When multiple tests can safely share the same authenticated identity, Playwright provides a way to reuse authenticated browser state instead.

What is storageState in Playwright?

After authentication, the browser keeps information that represents the signed-in session, such as cookies and browser storage.

Playwright can save reusable browser state to a file using storageState().

For example:

await page.context().storageState({
  path: 'playwright/.auth/user.json'
});

A later browser context can load that state and start already authenticated instead of repeating the SSO login UI.

Think of storageState as saving the authenticated browser state for reuse.

How do you reuse an SSO login with storageState?

A common Playwright pattern is:

  1. Create a dedicated authentication setup test.

  2. Sign in through the identity provider.

  3. Wait until authentication has fully completed.

  4. Save the authenticated browser state.

  5. Configure business-test projects to use the saved state.

Step 1: Create an authentication setup test

Create a location for the authentication state and keep it out of source control.

For example:

playwright/
  .auth/
    user.json

Add the directory to .gitignore:

playwright/.auth

Treat playwright/.auth/user.json as sensitive data. It can contain cookies or other browser state representing the authenticated test account.

Step 2: Authenticate and save the browser state

Create an authentication setup test:

JavaScript
import {
  test as setup,
  expect
} from '@playwright/test';

import path from 'path';

const authFile = path.join(
  __dirname,
  '../playwright/.auth/user.json'
);

setup('authenticate', async ({ page }) => {
  await page.goto(process.env.APP_URL!);

  await page
    .getByLabel('Email')
    .fill(process.env.SSO_USER!);

  await page
    .getByRole('button', { name: 'Next' })
    .click();

  await page
    .getByLabel('Password')
    .fill(process.env.SSO_PASSWORD!);

  await page
    .getByRole('button', { name: 'Sign in' })
    .click();

  await page.waitForURL(`${process.env.APP_URL}/**`);

  await expect(
    page.getByRole('heading', {
      name: /home|dashboard/i
    })
  ).toBeVisible();

  await page.context().storageState({
    path: authFile
  });
});

The final assertion is important because an SSO flow can involve several redirects before the application has finished establishing the authenticated session.

Save the state only after you have reached a reliable signed-in state.

How do you connect storageState to your Playwright tests?

Configure a setup project and make the browser project depend on it.

For example:

JavaScript
import {
  defineConfig,
  devices
} from '@playwright/test';

export default defineConfig({
  projects: [
    {
      name: 'setup',
      testMatch: /.*\.setup\.ts/
    },
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
        storageState:
          'playwright/.auth/user.json'
      },
      dependencies: ['setup']
    }
  ]
});

The setup project performs authentication and saves the state.

The Chromium project then loads that state before running the business tests.

What does the business test look like after authentication reuse?

The business test no longer needs to contain the SSO steps:

JavaScript
import { test, expect } from '@playwright/test';

test('user can view orders', async ({ page }) => {
  await page.goto(
    `${process.env.APP_URL}/orders`
  );

  await expect(
    page.getByRole('heading', { name: 'Orders' })
  ).toBeVisible();
});

Authentication and business behavior are now separated.

The setup test is responsible for creating the authenticated browser state, while the Orders test focuses on the application behavior it needs to validate.

How do you run the authenticated Playwright test?

Run the configured project:

npx playwright test --project=chromium

The authentication setup runs first and creates:

playwright/.auth/user.json

The dependent tests then load the saved state.

If the state is valid, the Orders test should reach the authenticated application without displaying the SSO login form again.

Why should you protect the storageState file?

A saved authentication-state file can contain cookies or other browser state that represents the authenticated test account.

Treat it like a credential.

Do not:

  • commit the .auth directory to source control

  • expose the file unnecessarily

  • publish it as an unsecured CI artifact

  • assume that it is harmless because it does not contain the account password

When the authentication state expires, recreate it securely.

What happens when the Playwright suite grows?

A single reusable login is relatively straightforward. More complexity appears when the suite introduces multiple roles, parallel workers, expiring sessions, or different authentication-storage requirements.

Situation

Typical Playwright approach

What you need to manage

Saved login expires

Run authentication setup again and replace the saved state

When and how authentication state is refreshed

Several roles are tested

Save a separate state for each role

Mapping tests to the correct user and credentials

Parallel tests modify shared data

Use different accounts per worker

Test-account allocation

Authentication state is sensitive

Keep .auth out of source control

Protection of state files and source credentials

Application relies on sessionStorage

Add explicit save and restore logic

Additional authentication helper code

Authentication state expires during local development

Run the setup again

Refreshing local state when required

You do not need to solve every case on day one.

These considerations become more important as more tests, roles, and parallel executions share the authentication setup.

Does storageState include sessionStorage?

No. If the application relies on sessionStorage for authentication, additional save-and-restore logic is required.

This matters because an SSO flow may appear to authenticate correctly but still fail when the reused state does not include the storage mechanism the application depends on.

If a test using saved authentication state unexpectedly returns to the login page, check how the application stores its authenticated session.

How do you handle multiple user roles?

Do not assume that one saved authentication state should represent every user.

If the application needs tests for roles such as administrator, manager, and standard user, keep separate authenticated states and test identities for those roles.

Conceptually:

playwright/.auth/
  admin.json
  manager.json
  user.json

Each test project or fixture can then use the state appropriate to the role being tested.

What about parallel tests?

Sharing a single authenticated identity can be problematic when parallel tests modify the same server-side state.

In those cases, use separate test accounts rather than allowing multiple workers to interfere with one another through the same identity.

Authentication reuse and test-data isolation are related but different concerns.

A valid authenticated session does not prevent two tests from modifying the same account or application data at the same time.

Can SSO with MFA or Conditional Access be automated?

Your identity-provider policy still applies.

If the tenant requires a human push approval, device binding, MFA challenge, or another interactive control, the automation design must respect that requirement.

Use a dedicated test identity and an authentication policy approved for automated testing.

Do not weaken production authentication controls simply to make a test run unattended.

For authenticator-app based TOTP flows, see How to Automate TOTP Authentication in Playwright for the separate TOTP automation pattern.

How does Leapwork Play reuse an SSO login?

Leapwork Play uses a different reuse mechanism from Playwright's storageState.

In the confirmed Play workflow, you can:

  1. Record the SSO login once as a reusable test case such as LoginSSO.

  2. Save that login flow as a shared test case.

  3. Create a separate business test, such as an Orders test.

  4. Add Use test case: LoginSSO to the business test.

  5. Continue recording or adding the business steps.

  6. Run the complete test from Play.

When the business test references LoginSSO, Play runs the reusable login flow and then continues with the business test.

This keeps authentication separate from the business journey without copying the login steps into every test.

How do you record an SSO login in Leapwork Play?

1. Record the login

Create a small test case such as LoginSSO.

Start the Recorder and complete the approved Okta, Auth0, or Microsoft Entra ID sign-in flow.

Save the test after reaching a reliable signed-in state.

2. Create the business test

Create the test containing the business journey you want to validate.

For example, create an Orders test without copying the complete SSO flow into it.

3. Reference the reusable login

Add the saved login test case using:

Use test case: LoginSSO

Then continue with the business steps, such as opening Orders and validating the expected page content.

4. Run the complete test

Run the Orders test from the shared Play workspace.

Play runs the referenced LoginSSO test case and then continues with the Orders steps.

If the login journey changes, the reusable LoginSSO test case can be updated instead of copying the same changes into every business test that references it.

What is the difference between storageState vs. LoginSSO ?

The two approaches both reduce duplicated login logic, but they reuse authentication differently.

Area

Plain Playwright

Leapwork Play

Create the login

Write and maintain authentication setup code

Record LoginSSO in Play's built-in browser

Reuse

Load storageState through Playwright configuration

Add Use test case: LoginSSO to another test

Runtime behavior

Test can start with previously saved authentication state

Referenced LoginSSO flow runs as part of the test

Authentication state

Saved to an auth-state file

Login workflow is reused as a test case

Authoring

Maintain setup test, locators, and configuration

Recorded steps and generated Playwright are kept together in the workspace

Browser environment

Team manages the Playwright/browser environment

Play provides a built-in cloud browser and cloud execution

Shared maintenance

Maintain setup code, state files, and role/worker strategy

Update the shared LoginSSO test case referenced by business tests

Locator changes

Update affected locators/test code

Play includes self-healing capabilities that can help when application locators change

Identity-provider policy

IdP policy still applies

IdP policy still applies

The key technical difference is:

storageState reuses authenticated browser state. LoginSSO reuses the login workflow itself.

With storageState, a Playwright test can start already authenticated.

With the LoginSSO workflow described here, the login flow runs when the business test references it.

Where does Leapwork Play reduce setup for the QA author?

In the confirmed workflow, Play brings the recorder, built-in cloud browser, reusable test case, generated Playwright, and execution into the same shared workspace.

Instead of asking every QA author to work directly with:

  • auth.setup.ts

  • authentication-state files

  • project dependencies

  • storageState configuration

  • local recorder setup

the SSO journey can be recorded as a visible reusable LoginSSO test case and referenced from business tests.

This does not bypass the identity provider. Okta, Auth0, Microsoft Entra ID, MFA, Conditional Access, and other configured identity policies continue to apply.

Record once and reuse the SSO login in Leapwork Play

Leapwork Play recording an SSO login and reusing the LoginSSO test case from an Orders Playwright test.

Best practices for Playwright SSO testing

  • Use a dedicated test identity approved for automation.

  • Keep usernames, passwords, client secrets, tokens, and other authentication secrets out of test source.

  • Protect saved storageState files as sensitive authentication material.

  • Wait for a clear authenticated application state before saving storageState.

  • Keep reusable authentication logic separate from business-test logic.

  • Refresh authentication state when it expires instead of weakening identity-provider policies.

  • Use separate accounts when parallel tests modify shared server-side data.

  • Keep separate authentication state for different roles.

  • Respect MFA, Conditional Access, device-binding, and other IdP policies.

  • Avoid exposing authentication information in logs and CI artifacts.

Troubleshooting SSO authentication in Playwright

The test returns to the login page

The saved authentication state may have expired, may have been captured before authentication completed, or may not include the storage mechanism the application relies on.

Confirm that the authentication setup reaches a clearly signed-in application state before saving storageState.

Tests interfere with one another in CI

If parallel tests modify server-side state using the same account, use separate accounts per worker rather than sharing one authenticated identity.

The application uses sessionStorage

Playwright does not persist sessionStorage through storageState. Add explicit save-and-restore logic if the application's authentication depends on it.

MFA prevents unattended execution

Use an approved test identity and an authentication policy designed for automated testing. Do not disable or weaken production authentication controls simply to make the test unattended.

The Play recording reaches an unexpected tenant screen

Treat the screen as part of the actual SSO flow.

Review the generated steps and confirm the test identity, environment, and identity-provider policy before changing the test.

Frequently asked questions

Can Playwright automate SSO login?

Yes. Playwright can automate the browser-based authentication flow through an identity provider such as Okta, Auth0, or Microsoft Entra ID.

Can Playwright reuse an SSO login?

Yes. A setup project can authenticate once, save browser state using storageState, and allow dependent tests to start with that authenticated state.

Should every Playwright test sign in through the identity provider?

Usually not when tests can safely reuse authentication state. Separating authentication from business tests avoids duplicating the same SSO flow throughout the suite.

What does storageState do?

storageState saves reusable browser state such as cookies and supported browser storage. A later browser context can load that state and start with the saved authentication.

Is a storageState file sensitive?

Yes. It can contain cookies or other browser state representing an authenticated account. Keep authentication-state files out of source control and protect them like credentials.

Does storageState include sessionStorage?

No. Applications that depend on sessionStorage require additional save-and-restore logic.

Can one saved authentication state be used for every role?

No. Use separate test identities and authentication states for the roles the application needs to test.

How do I handle SSO with parallel Playwright tests?

If tests modify shared server-side data, use separate test accounts per worker rather than having parallel workers share the same identity.

Is LoginSSO in Leapwork Play the same as Playwright storageState?

No. They reuse authentication differently. storageState saves browser authentication state so a Playwright test can start already authenticated. LoginSSO is a reusable login test case whose login flow runs when another test references it.

Does Leapwork Play bypass Okta, Auth0, Entra ID, MFA, or Conditional Access?

No. The configured identity-provider policy still applies. Use a test identity and authentication setup approved by your security team.

What happens when the shared SSO login changes in Play?

Update the reusable LoginSSO test case. Business tests that reference LoginSSO continue to use that shared test case. Play also includes self-healing capabilities that can help when application elements change.

Can I automate TOTP-based MFA as part of an SSO flow?

TOTP requires generating the current one-time password from the shared MFA secret. See How to Automate TOTP Authentication in Playwright for the TOTP-specific pattern.