Authentication
Test logged-in areas of your application by configuring SimuTest with one of five authentication methods — from cookie injection to automated form login.
Overview
Most applications gate their most important flows behind authentication — dashboards, checkout, account settings, admin panels. Without the ability to simulate authenticated sessions, UX testing only covers your public pages.
SimuTest supports five authentication methods. Choose the one that matches how your application manages session state:
| Method | Best for | Setup complexity |
|---|---|---|
| storage_state | Existing Playwright auth state files, complex session scenarios | Medium |
| cookies | Session cookies exported from browser DevTools | Low |
| token | JWT or API tokens stored in localStorage, sessionStorage, or a cookie | Low |
| credentials | Applications with standard username/password login forms | Low |
| http_basic | Staging environments protected by HTTP Basic authentication | Minimal |
Security note: Never hardcode credentials or tokens directly in your configuration files. Always use environment variables with the _env suffix in YAML, or read from process.env in the SDK. See Security Best Practices below.
Method 1: Storage State
Storage state is the most flexible authentication method. It mirrors Playwright'sstorageStateformat, allowing you to inject cookies and localStorage/sessionStorage values simultaneously. Use this method when you have an existing Playwright authentication setup or when your application stores session state in multiple places.
YAML configuration
Use value_env to reference an environment variable for sensitive cookie values.
tests:
- name: "Dashboard Export (storage state)"
url: https://app.example.com/dashboard
task: "Export the monthly analytics report"
auth:
method: storage_state
cookies:
- name: session
value_env: SESSION_COOKIE
domain: app.example.com
path: /
httpOnly: true
secure: true
sameSite: Lax
origins:
- origin: https://app.example.com
localStorage:
- name: user_prefs
value: '{"theme":"dark","locale":"en-US"}'
criteria:
- task_completion
- navigation_claritySDK usage
import { SimuTest } from '@simutest/sdk';
const simutest = new SimuTest({ apiKey: process.env.SIMUTEST_API_KEY! });
const results = await simutest.test({
url: 'https://app.example.com/dashboard',
task: 'Export the monthly analytics report',
auth: {
method: 'storage_state',
storageState: {
cookies: [
{
name: 'session',
value: process.env.SESSION_COOKIE!,
domain: 'app.example.com',
path: '/',
httpOnly: true,
secure: true,
sameSite: 'Lax',
},
],
origins: [
{
origin: 'https://app.example.com',
localStorage: [
{ name: 'user_prefs', value: '{"theme":"dark","locale":"en-US"}' },
],
},
],
},
},
});Exporting storage state from Playwright
If your project already uses Playwright, you can export an authenticated storage state with await page.context().storageState({ path: 'auth.json' }) after a successful login. Pass the resulting JSON directly to the storageState option.
Method 3: Token
Token auth injects a JWT or API token into your application's client-side storage before the test session navigates to the target URL. This is the recommended method for single-page applications that read auth state from localStorage or sessionStorage on load.
The storage_type field accepts three values:
| storage_type | Where the token is injected | Common use case |
|---|---|---|
| localStorage | window.localStorage[key] | SPA frameworks (React, Vue, Angular) |
| sessionStorage | window.sessionStorage[key] | Session-scoped auth flows |
| cookie | HTTP cookie with the specified key name | Server-side rendered apps reading token from cookie |
YAML configuration
Use token_env to reference the environment variable name that holds the token value. SimuTest reads the variable at runtime — the token is never stored in your config file.
tests:
- name: "Admin Panel (token auth)"
url: https://app.example.com/admin
task: "Navigate to user management and search for a user"
auth:
method: token
token_env: TEST_AUTH_TOKEN
storage_type: localStorage
key: authToken
criteria:
- task_completion
- navigation_claritySDK usage
import { SimuTest } from '@simutest/sdk';
const simutest = new SimuTest({ apiKey: process.env.SIMUTEST_API_KEY! });
const results = await simutest.test({
url: 'https://app.example.com/admin',
task: 'Navigate to user management and search for a user',
auth: {
method: 'token',
token: process.env.TEST_AUTH_TOKEN!,
storageType: 'localStorage', // 'localStorage' | 'sessionStorage' | 'cookie'
key: 'authToken',
},
});Method 4: Credentials
The credentials method automates a real login flow — SimuTest navigates to your login page, fills in the username and password fields, submits the form, and waits for the success URL before starting the test session. This is the most realistic auth method and works with any standard username/password form.
SimuTest uses sensible default selectors (input[type="email"], input[type="password"], button[type="submit"]) but you can override them with the selectors option for non-standard login forms.
YAML configuration
tests:
- name: "Dashboard UX (credentials auth)"
url: https://app.example.com/dashboard
task: "Find and export the monthly analytics report"
auth:
method: credentials
login_url: https://app.example.com/login
username_env: TEST_USERNAME
password_env: TEST_PASSWORD
success_url: https://app.example.com/dashboard
# Optional: custom selectors if your login form is non-standard
selectors:
username: 'input[name="email"]'
password: 'input[name="password"]'
submit: 'button[type="submit"]'
criteria:
- task_completion
- navigation_claritySDK usage
import { SimuTest } from '@simutest/sdk';
const simutest = new SimuTest({ apiKey: process.env.SIMUTEST_API_KEY! });
const results = await simutest.test({
url: 'https://app.example.com/dashboard',
task: 'Find and export the monthly analytics report',
auth: {
method: 'credentials',
loginUrl: 'https://app.example.com/login',
username: process.env.TEST_USERNAME!,
password: process.env.TEST_PASSWORD!,
successUrl: 'https://app.example.com/dashboard',
// Optional: override selectors for non-standard login forms
selectors: {
username: 'input[name="email"]',
password: 'input[name="password"]',
submit: 'button[type="submit"]',
},
},
});Custom selectors
The selectors object accepts any valid CSS selector. Use this when your login form uses non-standard input types or when there are multiple forms on the login page. The selectors are evaluated in the context of the login_url page.
Method 5: HTTP Basic
HTTP Basic authentication is commonly used to protect staging environments and preview deployments from public access. SimuTest handles the browser authentication dialog automatically by injecting credentials at the network level.
This method sends credentials as a Base64-encoded Authorization header with every request to the target origin — matching the behavior of a browser that has already authenticated the realm.
YAML configuration
tests:
- name: "Staging Site (HTTP basic auth)"
url: https://staging.example.com
task: "Verify the homepage loads correctly"
auth:
method: http_basic
username_env: STAGING_USERNAME
password_env: STAGING_PASSWORD
criteria:
- visual_hierarchy
- content_claritySDK usage
import { SimuTest } from '@simutest/sdk';
const simutest = new SimuTest({ apiKey: process.env.SIMUTEST_API_KEY! });
const results = await simutest.test({
url: 'https://staging.example.com',
task: 'Verify the homepage loads correctly',
auth: {
method: 'http_basic',
username: process.env.STAGING_USERNAME!,
password: process.env.STAGING_PASSWORD!,
},
});Security Best Practices
Never hardcode secrets
Never put passwords, tokens, or cookie values directly in your simutest.yaml or SDK calls. Always reference environment variables using the _env suffix in YAML (e.g., token_env: MY_TOKEN) or read from process.env in the SDK.
Use dedicated test accounts
Create a dedicated test user account (e.g., simutest@yourcompany.com) with minimal permissions. Never use a production admin account. Test accounts should have read-only access where possible and should not have access to sensitive customer data.
Use st_test_ API keys for development
SimuTest issues separate API keys for development (st_test_) and production (st_live_). Use test keys in local development and CI; reserve live keys for production monitoring. Test keys are rate-limited and do not consume production session quota.
Rotate credentials regularly
Rotate test account passwords and API tokens on a regular schedule (quarterly at minimum). Update the corresponding CI/CD secrets immediately after rotation. For short-lived JWTs, generate a fresh token as part of your CI pipeline rather than storing a long-lived one.
Add simutest.yaml to .gitignore if needed
Your simutest.yaml is safe to commit as long as you use _env references for all secrets. If you ever accidentally inline a credential, revoke it immediately and rotate.
Environment Variables
SimuTest reads environment variables at runtime. Use a .env.local file for local development (never committed) and CI/CD secrets for pipeline runs.
.env.local
# .env.local — never commit this file
SIMUTEST_API_KEY=st_live_xxxxxxxxxxxxxxxxxxxxxxxx
# Test credentials (use read-only, non-production accounts)
TEST_USERNAME=simutest@yourcompany.com
TEST_PASSWORD=...
# Token auth
TEST_AUTH_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Staging basic auth
STAGING_USERNAME=preview
STAGING_PASSWORD=...
# Session cookies (export from browser DevTools)
SESSION_COOKIE=abc123...GitHub Actions workflow (referencing repository secrets)
# .github/workflows/simutest.yml
name: SimuTest UX Audit
on:
pull_request:
branches: [main]
jobs:
simutest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run SimuTest
run: npx simutest run
env:
SIMUTEST_API_KEY: ${{ secrets.SIMUTEST_API_KEY }}
TEST_USERNAME: ${{ secrets.TEST_USERNAME }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
TEST_AUTH_TOKEN: ${{ secrets.TEST_AUTH_TOKEN }}CI/CD secrets setup
- GitHub Actions: Settings → Secrets and variables → Actions → New repository secret
- GitLab CI: Settings → CI/CD → Variables → Add variable (mark as Masked)
- CircleCI: Project Settings → Environment Variables → Add variable
Troubleshooting
credentials auth: wrong selectors
If the login flow fails, the most common cause is that SimuTest cannot locate the username or password input using the default selectors. Open your login page in Chrome DevTools and inspect the form inputs to find the correct CSS selectors, then set them explicitly using the selectors option.
Enable debug mode (SIMUTEST_DEBUG=auth) to see a screenshot of the login page at the point of failure.
CAPTCHA or 2FA blocking automated login
If your login form includes CAPTCHA or two-factor authentication, the credentials method cannot bypass it. Use storage_state or token auth instead — authenticate manually once to obtain the session state, then inject it directly.
Token or cookie has expired
If test sessions are redirected to the login page, your injected token or cookie has likely expired. For short-lived JWTs, generate a fresh token as part of your CI pipeline using your application's auth API before running SimuTest. Alternatively, switch to credentials auth, which always obtains a fresh session.
CORS errors with token injection
If your app reads the auth token via a fetch call to a different origin before navigating, localStorage injection may not work as expected because localStorage is origin-scoped. Ensure the origin in your storage state config exactly matches the origin of the page being tested (including protocol and port).
On this page