How to test role-based access with multiple authenticated users in Playwright

Playwright can reuse authenticated browser state with storageState, but role-based access tests usually need one signed-in user per role. In a real application, different roles often see different pages, buttons, and navigation options. An admin may be able to create or manage records, while an editor may only update content and a viewer may only read it. To test those boundaries properly, each role should authenticate with its own test account and save its own browser state.

That way, the test suite can verify more than just whether a user can log in. It can confirm that the right people can reach the right screens, that restricted actions are hidden or blocked, and that one role cannot accidentally access another role’s permissions. For example, a profile menu might show extra options for an admin, while a normal user only sees the shared items. Keeping one saved state per role also makes the tests easier to maintain, because each test runs with the identity it was meant to validate.

That is manageable in a small suite. It becomes test infrastructure when multiple roles, shared data, and parallel runs all depend on the same authentication setup.

Related guides

If you still need the authentication foundation, start with How to automate SSO login in Playwright with Okta, Auth0, or Microsoft Entra ID. For state expiry, workers, shards, and CI, see “How to keep authentication state fresh across long Playwright CI runs”.

Already know the Playwright pattern?

Jump to the Leapwork Play section to see how one parameterized login subflow can be reused for admin, normal-user, and future roles without creating a separate login implementation for each role. How does the same role-based workflow look in Leapwork Play?

Before you start

  • A Playwright Test project with reusable authentication already working.

  • At least two approved test identities, such as Admin and Viewer.

  • Credentials supplied through environment variables or an approved secret manager.

  • A written permission matrix that states what each role should be allowed and denied

Why QA engineers use Play for this workflow

  • Stop debugging the wrong user state. The role is explicit in the test, so you can immediately see whether the scenario is running as Admin, Viewer, or another user instead of tracing storageState, projects, and fixtures.

  • Change the role, not the authentication setup. Switch ADMIN to VIEWER and rerun the same flow to create a negative permission test without rebuilding the surrounding login configuration.

  • Fix login once. When the sign-in journey changes, update the reusable Login test case and let the role-based tests continue to reference it.

  • See the permission intent directly in the test. A QA engineer can read Viewer → Login → Admin capability should be denied without first understanding how the authentication framework is wired.

  • Your framework develops tribal knowledge. After a couple of months, authentication may involve setup projects, fixtures, helpers, environment variables, project dependencies and CI configuration. Playwright provides these mechanisms because serious suites need them. The downside is that changing a business test can require understanding framework code written by the person who designed all of those layers.

If you continue with the traditional Playwright approach, none of this is impossible, but the QA engineer increasingly works across auth setup files, storageState artifacts, project configuration, fixtures, credentials, and the business test itself just to understand why a role-based test is behaving differently. The permission check may be simple; diagnosing the authentication context around it is often where the time goes.

This guide first shows the clean Playwright implementation, then uses the same Admin/Viewer scenario in Play so you can compare the authoring and debugging experience yourself.

Playwright

Start with the permission matrix, not the test code

A seasoned Playwright implementation starts by making the expected authorization model explicit. That keeps the tests focused on permissions rather than on the mechanics of signing in.

Capability

Admin

Viewer

Open the admin area

Allowed

Denied

Manage users

Allowed

Denied

View own profile

Allowed

Allowed

Best practice: test the deny path too

Do not stop at “the button is hidden.” Where it matters, also try the protected URL or operation directly and verify that the application rejects the Viewer. UI visibility is useful evidence, but the authorization boundary should still hold when someone bypasses the navigation.

Authenticate each role once and keep the login logic in one place

Use the login helper you already created in the SSO guide. The role-specific setup should only decide which identity to use and where to save its authenticated state.

This keeps role data separate while avoiding two nearly identical login implementations. If you add another role later, add another role definition and the corresponding permission tests rather than cloning the sign-in flow.

Map authenticated roles to Playwright projects

Projects give each role a named configuration. That makes the role visible in the test run and keeps the selected authentication state out of individual business tests.

Verify both allowed access and denied access

Role-based tests are strongest when they validate the permission boundary from more than one direction.

What to verify

Admin example

Viewer example

Visible controls

Manage users is visible

Manage users is hidden

Direct navigation

/admin opens normally

/admin is denied or redirected

Protected action

Management action succeeds

Protected action is rejected

Why this matters

A missing Admin button is not enough on its own. A Viewer who knows the URL should still be denied. If the application exposes a protected backend operation, validate that boundary as well.

What changes when role-based tests run in parallel?

If parallel tests only read data, the same role account may be reusable. If they create or modify shared server-side data, use separate approved accounts or isolate the data each worker touches. The detailed worker, shard, state-refresh, and CI patterns are covered in the authentication-freshness guide, so they are not repeated here.

Security reminder

Treat every saved role state as sensitive. Keep it out of source control, and do not store passwords or tokens in test data files in plain text.

What does the Playwright project now own?

For a small role matrix, this is straightforward. As the number of roles and tests grows, the project owns the role-to-account mapping, authenticated state files, project configuration, permission assertions, and any account/data isolation needed for parallel execution. Playwright can handle all of it; the practical question is how much of that setup you want QA authors to maintain directly.

Leapwork Play

How does the same role-based workflow look in Leapwork Play?

The Play workflow in this demo uses one parameterized login test case instead of one login implementation per role. The calling test passes a role ID, the reusable login resolves the matching identity, signs in, and then returns control to the role-specific business test. The login logic stays in one place even as new roles are added.

Parameterization means using the same reusable test logic with different input values. In this example, the Login test stays the same while the calling test passes a different role ID, such as Admin or Viewer, to select the right user.

In this example, Admin and Viewer share several common menu options, while Leapwork Play Monitor and Admin Section are available only to the Admin. The same parameterized Login is used for both roles, the role-specific validation determines whether the expected access is present or denied.

Scenario / role data

Reusable login test case

Role-specific validation

Expected result

Admin role ID + secure credential reference

Login parameterized with Admin

Account and settings; Workspace settings; Documentation; Join Community; About Leapwork Play; Leapwork Play Monitor; Admin Section; Log out

✅ Pass

Viewer role ID + secure credential reference

Same reusable Login, parameterized with Viewer

Account and settings; Workspace settings; Documentation; Join Community; About Leapwork Play; Log out. Leapwork Play Monitor and Admin Section are not visible.

✅ Pass

Negative RBAC test: change the role from Admin to Viewer while keeping an Admin-only expectation

Same reusable Login, now passed the Viewer role

Viewer menu loads correctly, but Leapwork Play Monitor is absent

Fails as expected, confirming the Viewer does not have the Admin capability

Keep secrets out of the data file

The demo uses a role ID to select the matching row from a data source. For production use, keep role mapping and non-secret test data in that data source, but resolve usernames, passwords, tokens, or other secrets from an approved secret store rather than storing them in plain text.

In a RunList, each Play test case runs independently in its own short-lived execution environment. When a test references the reusable Login subflow, that test case performs its own login. The reusable asset is the login workflow; authenticated browser state is not shared across the role tests.

Why this is useful for QA teams

The role selection stays visible in the test design. Adding a new role does not require another copy of the login logic, and QA authors do not have to wire separate storageState files and Playwright projects into each business test. Play also provides a built-in cloud browser and managed cloud execution for the test workflow.

Test cases

  • Login: A single reusable test case handles signing in to the app. Instead of hardcoding one identity, the login fields (username, password, role ID) are parameterized so the same test case can authenticate as any role, depending on what's passed in.

  • Admin profile validation: Rather than repeating the sign-in steps, this test case calls Test case 1 and passes in the admin role ID. That role ID is used to look up the matching credentials from the Excel data file, so the login step signs in as an admin without any of the login logic being duplicated. Once signed in, the test continues on to validate the admin's profile values.

  • Normal user profile validation: Same pattern, different role. This test case also reuses Test case 1, but passes in the normal user's role ID instead. The login test case pulls the corresponding credentials from the Excel file, signs in as that user, and the test proceeds to validate that user's profile values.

Because the role ID drives which row is picked from the Excel file, adding a new role to test doesn't mean writing a new login flow it just means adding a new row to the data source and pointing a test case at the right ID. The login logic itself stays in one place, so if the sign-in flow ever changes, it only needs to be updated once, in Test case 1, rather than hunted down across every test that signs in.

Watch: reuse one parameterized Login workflow across roles

This walkthrough uses Play to test Play and shows the same reusable Login test case being used with different role inputs, such as Admin and Normal User. Each role-specific test continues with its own permission checks after authentication. It also includes a negative RBAC check where changing the role causes an Admin-only validation to fail as expected, confirming that the access boundary is enforced.

Playwright vs Leapwork Play for role-based access testing

Area

Playwright

Leapwork Play

Role representation

Separate test identities plus storageState/project configuration.

Role ID or role data passed to a reusable parameterized Login subflow.

Login reuse

Reuse saved authenticated browser state.

Reuse the login workflow; each test case signs in when the subflow is referenced.

Add a new role

Add identity/state configuration and role-specific permission tests.

Add the role data/secret mapping and role-specific validation; the Login logic stays shared.

Auth artifacts

Protect one authenticated state file per role.

No shared storageState file is carried across these role tests.

Parallel execution

Use separate accounts or isolated data when workers could conflict.

Test cases execute independently; use different test users where account or data conflicts are possible.

Authoring visibility

Role setup may be spread across auth setup, config, fixtures, and specs.

Reusable Login and role-specific business tests are visible in the shared workspace.

Execution

Team runs and maintains the Playwright browser/runtime environment.

Built-in cloud browser and managed cloud execution.

Best Practices

  • Define the permission matrix before writing tests, and keep it aligned with the product or security requirements.

  • Test both positive and negative permissions. A role should prove what it can do and what it cannot do.

  • Use a dedicated approved test identity per role; use more identities when parallel tests would otherwise conflict.

  • Keep role authentication state and credentials separate. Never store passwords or tokens in source control or plain-text data files.

  • When a role assignment changes, re-authenticate before validating the new permissions so the test uses current claims/session state.

  • Use multiple BrowserContexts only for workflows that genuinely require two users to participate in the same scenario.

Troubleshooting

Issue

Likely cause

What to check

Viewer gets Admin permissions

Wrong role state or role-to-project mapping

Confirm the test is using the Viewer state/project and the expected test account.

Viewer cannot see the button, but a protected route/action still works

UI is hiding the control but authorization is not enforced at the boundary

Test the protected URL or operation directly and raise it as an authorization defect if it succeeds.

Permissions are wrong after an administrator changes the user role

Existing session still reflects old claims/role data

Re-authenticate the user before validating the changed role.

Parallel role tests interfere with each other

Tests share the same account or backend data

Use separate test users or isolate the records each test modifies.

Play test signs in with the wrong role

Role ID, data row, or secret mapping is wrong

Trace the role parameter passed into the shared Login and verify the mapped identity before the business steps run.

Frequently asked questions

Can one storageState file be used for every role?

No. The saved state represents a specific signed-in identity. Keep separate authenticated state for the roles you need to validate.

Should I write a separate login implementation for every role?

Usually no. Keep one login helper and vary the identity/state. The role-specific tests should focus on permissions rather than repeating sign-in mechanics.

How do I test two signed-in users in one Playwright scenario?

Create two independent BrowserContexts and initialize each one with the appropriate role state. This gives both users isolated cookies and storage inside the same test.

What if an administrator changes a user’s role?

Re-authenticate before validating the new role. Existing session claims or application state may still represent the previous permissions.

Does Leapwork Play share one authenticated session across all role tests?

No. In the workflow shown here, each test case runs independently and performs the reusable Login flow when it is referenced. The login workflow is shared; the authenticated session is not.

Do I need a new Login test case for every new role in Play?

Not when the login is parameterized. Add the role data and secure credential mapping, then pass the new role into the same reusable Login test case.