ZERODROP
← INTEGRATIONSDOCS
PlaywrightAuth0GitHub Actions

Testing Auth0 Email Flows with Playwright

Auth0 sends OTP codes and magic links for passwordless authentication and email verification. Testing these flows in CI requires catching real emails. Here's the complete setup.

The problem

Auth0's passwordless email flow sends a one-time code to verify identity. Most teams skip E2E testing this flow because intercepting Auth0's emails in CI is complex. ZeroDrop makes it straightforward — generate a disposable inbox, use it as the test email, catch the OTP automatically.

Install

npm install zerodrop-client

Testing Auth0 passwordless OTP

import { test, expect } from '@playwright/test';
import { ZeroDrop } from 'zerodrop-client';

const mail = new ZeroDrop();

test('Auth0 passwordless email OTP', async ({ page }) => {
  const inbox = process.env.TEST_INBOX ?? mail.generateInbox();

  // 1. Navigate to login
  await page.goto('/login');

  // 2. Enter disposable email on Auth0 Universal Login
  await page.fill('[name="username"]', inbox);
  await page.click('[name="action"]');

  // 3. Auth0 sends OTP to inbox
  await expect(page.getByText('code')).toBeVisible({ timeout: 5000 });

  // 4. Catch the OTP — auto-extracted, no regex
  const email = await mail.waitForLatest(inbox, { timeout: 30000 });

  expect(email.otp).not.toBeNull();

  // 5. Enter OTP
  await page.fill('[name="otp"]', email.otp!);
  await page.click('[name="action"]');

  // 6. Should be authenticated and redirected
  await expect(page).toHaveURL('/dashboard');
});

Testing Auth0 email verification on signup

test('Auth0 signup email verification', async ({ page }) => {
  const inbox = process.env.TEST_INBOX ?? mail.generateInbox();

  // Sign up with disposable inbox
  await page.goto('/login');
  await page.click('[data-action="sign-up"]');
  await page.fill('[name="email"]', inbox);
  await page.fill('[name="password"]', 'TestPassword123!');
  await page.click('[name="action"]');

  // Auth0 sends verification email
  const email = await mail.waitForLatest(inbox, { timeout: 30000 });

  expect(email.magicLink).not.toBeNull();

  // Click verification link
  await page.goto(email.magicLink!);

  // Should be verified and signed in
  await expect(page).toHaveURL('/dashboard');
});

GitHub Actions workflow

name: E2E Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npx playwright install --with-deps chromium

      - name: Generate test inbox
        id: inbox
        uses: zerodrop-dev/create-inbox@8706a59 # v1.0.0

      - name: Run E2E tests
        run: npx playwright test
        env:
          TEST_INBOX: ${{ steps.inbox.outputs.inbox }}
          AUTH0_DOMAIN: ${{ secrets.AUTH0_DOMAIN }}
          AUTH0_CLIENT_ID: ${{ secrets.AUTH0_CLIENT_ID }}
          AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_CLIENT_SECRET }}
          NEXT_PUBLIC_URL: ${{ secrets.STAGING_URL }}

Ready to test your Auth0 flows?

Free tier. No signup. No Docker. Works in CI in 5 minutes.

OPEN INBOX →

RELATED GUIDES

Playwright + NextAuthPlaywright + ClerkFull Playwright guide