100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Testing

Authentication and Storage State Reuse

Save and reuse Playwright's storageState to skip repeated UI logins, share auth across projects, and manage multiple user roles.

Network & MockingIntermediate8 min readJul 10, 2026
Analogies

Authentication and Storage State Reuse

Playwright's storageState captures every cookie and origin-scoped localStorage entry present in a browser context after a successful login, and saving it to a JSON file lets every subsequent test load that same authenticated state instantly instead of repeating the actual login flow, typing a username, a password, clicking submit, waiting for a redirect, in every single test file.

🏏

Cricket analogy: It is like a team keeping a pre-approved squad list from the toss so every subsequent innings just references that same list instantly, instead of re-verifying every player's eligibility from scratch before each over.

Saving Storage State

After performing a login, whether by driving the UI form or by calling the login endpoint directly through the request context, context.storageState({ path: 'auth.json' }) serializes every cookie and origin's localStorage into a JSON file, which can be committed to a fixtures directory for local development or generated fresh at the start of every CI run to avoid depending on stale, possibly-expired session data.

🏏

Cricket analogy: It is like a curator taking a detailed soil and moisture reading of the pitch on the morning of the match and writing it into a report, a snapshot that captures the exact state at that moment for reference during the day's play.

javascript
// auth.setup.ts — a Playwright setup project that logs in once and saves storage state
import { test as setup, expect } from '@playwright/test';

const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('test.user@example.com');
  await page.getByLabel('Password').fill('S3curePass!');
  await page.getByRole('button', { name: 'Sign in' }).click();

  await expect(page.getByText('Welcome back')).toBeVisible();
  await page.context().storageState({ path: authFile });
});

Reusing Storage State with Projects and Fixtures

In modern playwright.config.ts, a dedicated setup project runs the login once and other projects declare dependencies: ['setup'] plus use: { storageState: 'playwright/.auth/user.json' }, so every test in those dependent projects starts each new browser context already authenticated, without any per-test login code at all.

🏏

Cricket analogy: It is like a designated opener who bats through the powerplay once to get the team off to a fast start, and every subsequent batter simply walks in already benefiting from that platform, instead of each one needing to rebuild momentum from zero.

Use test.use({ storageState: 'admin.json' }) inside a describe block to run just that subset of tests as a different role, layering role-specific auth on top of a project's default storageState without creating an entirely separate project.

Multiple Roles and Expiring Sessions

Applications with multiple user roles typically save separate storageState files per role, for example admin.json and viewer.json, generated by separate setup tests that log in as each role, and these files need periodic refreshing because session cookies or JWTs can expire, at which point every test depending on that stale file starts failing with the same authentication error, a signature that usually points straight to an outdated storage state rather than a real regression.

🏏

Cricket analogy: It is like a squad maintaining separate playing-XI lists for Test matches and T20Is, each needs updating separately as form changes, and if one list goes stale, every selection meeting based on it makes the same outdated call.

storageState files often contain real-looking, sometimes long-lived session tokens. Keep them out of public repositories, add them to .gitignore, and prefer regenerating them fresh on every CI run through a setup project rather than committing long-lived credentials that could be replayed if leaked.

  • storageState captures cookies and origin-scoped localStorage after a successful login.
  • context.storageState({ path }) serializes that state to a JSON file for reuse.
  • A setup project that logs in once, paired with dependencies and use.storageState, avoids per-test logins.
  • test.use({ storageState }) inside a describe block layers a different role onto a subset of tests.
  • Multiple roles typically need separate storageState files, each refreshed on its own schedule.
  • Expired session tokens in a stale storageState file cause many tests to fail with the same auth error.
  • Never commit long-lived storageState credentials to a public repo; regenerate them per CI run instead.

Practice what you learned

Was this page helpful?

Topics covered

#Testing#PlaywrightStudyNotes#TestingQA#AuthenticationAndStorageStateReuse#Authentication#Storage#State#Reuse#Security#StudyNotes#SkillVeris