Blog / QA Automation

How to Handle Authentication in Playwright: Session Reuse Guide

How to Handle Authentication in Playwright: Session Reuse Guide

The Authentication Bottleneck in Automated Testing

When QA teams write automated test suites, authentication is often one of the biggest bottlenecks.

If your application has 100 test cases that check user settings, billing details, or dashboard views, you need to be logged in to run them. If every single test case logs in manually by entering username/password and clicking submit, your test suite runs incredibly slow, and you risk rate-limiting your test accounts.

Fortunately, Playwright offers a native solution to this problem: Storage State.

By logging in once, capturing the session cookies and local storage tokens, and reusing them across all test cases, you can drastically speed up your test execution and keep your test pipeline highly reliable. Let's look at how to set this up step-by-step.


1. Understanding Playwright's Storage State

In modern web applications, login states are maintained using cookies, localStorage, or sessionStorage tokens.

Playwright allows you to save this exact state into a local JSON file using the command:

await context.storageState({ path: 'state.json' });

When you launch a new browser context for a subsequent test, you can pass this state.json file as an configuration parameter. The browser opens pre-authenticated, skipping the login screen entirely.


2. Step 1: Writing the Authentication Setup Script

First, we create a setup script that logs into the application once and saves the state. We place this inside a file (e.g., tests/auth.setup.ts):

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

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

setup('authenticate user', async ({ page }) => {
  // Navigate to login page
  await page.goto('https://example.com/login');

  // Fill in credentials
  await page.getByPlaceholder('Username').fill('test_user');
  await page.getByPlaceholder('Password').fill('secure_password123');
  
  // Click submit and wait for dashboard navigation
  await page.getByRole('button', { name: 'Sign In' }).click();
  await expect(page).toHaveURL(/.*dashboard/);

  // Save storage state to local JSON file
  await page.context().storageState({ path: authFile });
});

3. Step 2: Configuring Playwright to Run Setup First

Next, we update the playwright.config.ts configuration file. We define a dependency project so that the setup script runs before any of our actual tests run:

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

export default defineConfig({
  projects: [
    // Setup Project
    {
      name: 'setup',
      testMatch: /auth\.setup\.ts/,
    },
    // Main Testing Project using Chrome
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
        // Use the storage state generated by the setup project
        storageState: 'playwright/.auth/user.json',
      },
      dependencies: ['setup'],
    },
  ],
});

By adding dependencies: ['setup'], Playwright guarantees it will run auth.setup.ts once, generate the user.json file, and then feed it to the main testing projects.


4. Step 3: Writing Pre-Authenticated Tests

Now, when you write your regular test scripts, they don't need any login blocks. They open directly on the pages you want to validate, saving valuable seconds per test:

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

test('inspect dashboard statistics', async ({ page }) => {
  // Page is already logged in!
  await page.goto('https://example.com/dashboard');
  
  // Directly verify authenticated features
  await expect(page.getByRole('heading', { name: 'Welcome Back' })).toBeVisible();
  await expect(page.locator('.revenue-card')).toContainText('$');
});

test('update user profile preferences', async ({ page }) => {
  await page.goto('https://example.com/settings');
  await page.getByLabel('Dark Mode').check();
  await page.getByRole('button', { name: 'Save Changes' }).click();
  await expect(page.getByText('Settings Saved')).toBeVisible();
});

Benefits of Storage State Automation

Implementing Playwright's auth state architecture provides key benefits:

  • Massive Speed Increases: Instead of doing 100 login cycles, you do 1. Your test suite runtime can drop by 60-80%.
  • Flake Reduction: The login screen is often the most dynamic part of the app (subject to CAPTCHAs, MFA prompts, or database slowdowns). Skipping it makes tests stable.
  • Realistic User Simulation: Browser contexts are completely isolated, ensuring that test states do not bleed into one another while sharing authentication credentials.

If you are a QA Engineer ready to build professional automation frameworks, learning setup orchestrations and config patterns is crucial. Dive into full-stack testing with our Playwright TypeScript Masterclass to master API integration, custom fixtures, and CI/CD pipelines.

Want to master modern web testing with Playwright? Deep dive into storage state, page contexts, and API automation in our Playwright TypeScript Masterclass, honestly.