Playwright Authentication: Login Once, Run Tests Fast
Master Playwright authentication with storageState, globalSetup, and shared credentials. Skip the login UI in every test — full code examples and gotchas.
· 9 min read
Logging in through the UI in every Playwright test is the single biggest cause of slow suites. Playwright's `storageState` feature lets you log in once, save the session, and reuse it across hundreds of tests. Here is how to do it right.
The pattern in 60 seconds
1. In a `globalSetup` script, drive the login flow once. 2. Save the resulting cookies and localStorage with `page.context().storageState({ path: 'auth.json' })`. 3. In `playwright.config.ts`, point `use.storageState` at `auth.json`. 4. Every test now starts already authenticated — no login UI required.
playwright.config.ts setup
`export default defineConfig({ globalSetup: require.resolve('./global-setup'), use: { storageState: 'auth.json', baseURL: process.env.BASE_URL } });`
Add `auth.json` to `.gitignore` — it contains live session cookies. Regenerate it on every CI run; never commit it.
The global-setup script
`import { chromium } from '@playwright/test'; export default async () => { const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto(`${process.env.BASE_URL}/login`); await page.fill('#email', process.env.TEST_EMAIL!); await page.fill('#password', process.env.TEST_PASSWORD!); await page.click('button[type=submit]'); await page.context().storageState({ path: 'auth.json' }); await browser.close(); };`
Where to store the credentials
Hardcoded credentials in the script are an antipattern — they leak into git history and break the moment staging passwords rotate. Environment variables work, but they multiply across CI, local, and per-developer setups.
The clean pattern: store the credentials in a hosted catalog like TestAssets and have your global-setup script fetch them at runtime via the REST API. Same credentials your QA engineers paste manually, same credentials your suite logs in with — and rotation is one update in one place.
Multiple authenticated roles
Need an admin user and a regular user in the same suite? Run global-setup multiple times, save `admin-auth.json` and `user-auth.json`, then use Playwright's `projects` config to assign each storage state to a subset of tests.
Token-based APIs
For APIs that use bearer tokens instead of cookies, do the login once, capture the token, and inject it as an Authorization header on the request fixture. Same idea, simpler implementation.
Common pitfalls
Sessions expire — your CI suite will start failing the day the token TTL runs out. Always regenerate `auth.json` at the start of each run. CSRF tokens — some apps tie sessions to CSRF; storageState alone may not be enough, you may need to refresh tokens per test. Multi-step MFA — if production has MFA, give your test users an MFA bypass or a service account.