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_URLfor the application URL. -
SSO_USERfor the test username. -
SSO_PASSWORDfor 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:
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:
-
Open the protected application.
-
Follow the redirect to the identity provider.
-
Enter the approved test credentials.
-
Complete the sign-in flow.
-
Wait until the browser has returned to a clearly authenticated application state.
-
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:
-
Create a dedicated authentication setup test.
-
Sign in through the identity provider.
-
Wait until authentication has fully completed.
-
Save the authenticated browser state.
-
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:
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:
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:
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
.authdirectory 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 |
Protection of state files and source credentials |
|
Application relies on |
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:
-
Record the SSO login once as a reusable test case such as
LoginSSO. -
Save that login flow as a shared test case.
-
Create a separate business test, such as an Orders test.
-
Add Use test case: LoginSSO to the business test.
-
Continue recording or adding the business steps.
-
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 |
|
Reuse |
Load |
Add Use test case: LoginSSO to another test |
|
Runtime behavior |
Test can start with previously saved authentication state |
Referenced |
|
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 |
|
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
-
storageStateconfiguration -
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
storageStatefiles 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.