Playwright Authentication

This chapter introduces how to handle authentication in Playwright, avoiding repeated logins for each test while maintaining test isolation.


The Core Problem of Authentication

Most web application tests require user login.

If every test performs the login flow from scratch, it will significantly slow down test execution.

Playwright's solution is:Authenticate once, save the state, and have all tests reuse it.。


Preparation: .auth Directory

Example

# Create a directory for storing authentication state
mkdir -p playwright/.auth

# Add to .gitignore (authentication state contains sensitive information)
echo 'playwright/.auth' >> .gitignore

.authThe file contains sensitive cookies and authentication tokens,and must never be committed to the code repository.。


Basic Approach: Shared Account + Setup Project

This is Playwright's recommended authentication approach, suitable for scenarios where all tests share the same test account.

Step 1: Create Authentication Setup

Example

// File path: tests/auth.setup.ts
import { test as setup } from '@playwright/test';

// Specify the authentication state save path
const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  // Perform login operation
  await page.goto('https://www.example.com/login');
  await page.getByLabel('username').fill('testuser');
  await page.getByLabel('password').fill('password123');
  await page.getByRole('button', { name: 'Login' }).click();

  // Wait for login to complete (confirm page navigation or user info appears)
  await page.waitForURL(/dashboard/);

  // Save the current authentication state (cookies, localStorage) to a file
  await page.context().storageState({ path: authFile });
});

Step 2: Configure Setup Project

Example

// File path: playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  projects: [
    // Setup project — runs only once, generates the authentication state file
    {
      name: 'setup',
      testMatch: /auth\.setup\.ts/,
    },

    // Actual test project — reuses the authentication state
    {
      name: 'chromium',
      use: {
        storageState: 'playwright/.auth/user.json',
      },
      dependencies: ['setup'],    // Depends on the setup project, ensuring setup runs first
    },
  ],
});

Step 3: Tests Directly Use Authentication State

Example

// File path: tests/dashboard.spec.ts
import { test, expect } from '@playwright/test';

test('View dashboard', async ({ page }) => {
  // Directly access a page that requires login; the page already carries the authentication state
  await page.goto('/dashboard');
  await expect(page.getByText('Welcome back, testuser')).toBeVisible();
});

Multiple Account Scenario

If different tests need to use different accounts, you can create multiple authentication state files.

Example

// Admin test
test.describe('Admin features', () => {
  test.use({ storageState: 'playwright/.auth/admin.json' });

  test('Manage users', async ({ page }) => {
    // Perform actions as an administrator
  });
});

// Regular user test
test.describe('Regular user features', () => {
  test.use({ storageState: 'playwright/.auth/user.json' });

  test('Browse content', async ({ page }) => {
    // Perform actions as a regular user
  });
});

Authentication via API Request (Recommended)

Performing the login flow through the UI is slow; a more efficient way is to call the login API directly.

Example

// File path: tests/auth.setup.ts
import { test as setup } from '@playwright/test';

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

setup('Authenticate via API', async ({ request }) => {
  // Call the login API directly, not through the browser UI
  const response = await request.post('https://www.example.com/api/login', {
    data: {
      username: 'testuser',
      password: 'password123',
    },
  });

  // Confirm login success
  const json = await response.json();
  console.log('Login successful, Token:', json.token);

  // Save the token as a cookie (simulating browser authentication state)
  // Note: storageState needs to be saved in the browser context
});

API authentication is faster and more reliable than UI authentication, and is recommended for priority use in real projects.


Summary of Applicable Scenarios for Authentication Approaches

ScenarioRecommended Approach
All tests use the same test accountSetup project + storageState
Different types of tests need different accountsMultiple storageState + test.use
Each test needs an independent accountCreate account and log in via API within each test
Limited account resourcesAuthenticate once in the Setup project, reuse for all
Other Extensions