How to Test Authentication Flows
Auth is where end-to-end tests get hard: sessions, tokens, magic links, SSO, 2FA. Here's what to cover, why it's tricky to automate, and how to do it without scripting every path.
Authentication is the front door to your product. If it breaks, nothing behind it matters — and it's the part of end-to-end testing teams most often get wrong, either skipping it because it's fiddly, or scripting it so rigidly that it breaks every time the login page changes.
What to cover
Authentication testing verifies that legitimate users can get in, stay in, and recover access, and that everyone else is kept out. Concretely:
- Sign-up. Account creation, including email verification if you require it, and the handling of a duplicate email or a weak password.
- Login — every method you support. Password, magic link, social / OAuth, SAML SSO. Each is a separate flow with separate failure modes; testing one doesn't cover the others.
- Session persistence. A logged-in user stays logged in across navigation, reloads, and new tabs. The session expires when it's supposed to, and expiry is handled gracefully rather than with a cryptic error.
- Recovery. Password reset end to end — request, email, link, new password, login with it. Re-authentication after a session times out mid-task, ideally returning the user to where they were.
- Authorisation boundaries. A regular user cannot reach an admin-only page by typing the URL. A logged-out user hitting a protected route is redirected to login, not shown a flash of protected content first. A user from one tenant cannot see another tenant's data.
- Multi-factor. The second factor is required when enabled, can be completed, and can't be skipped by manipulating the request.
The authorisation cases matter as much as the login cases — a broken permission check is a security incident, not just a bug.
Why auth is hard to automate
- It's stateful. Tokens, cookies, and sessions carry between steps. A test that mishandles them — reuses a stale token, drops a cookie, races a refresh — fails in ways that look random.
- It reaches outside your app. Verification emails, SMS codes, and third-party identity providers live in systems your test doesn't control.
- It changes often. Login and sign-up pages get redesigned and reworded frequently, which breaks selector-based scripts written against the old layout.
- It's a prerequisite for everything else. If the login step at the start of your suite is flaky, every downstream test inherits that flakiness, and you spend your debugging time in the wrong place.
Handling sessions, tokens, and 2FA
- Log in through the real UI at least once so the login flow itself stays covered. Then, for the rest of the suite, reuse the authenticated session — save the storage state after that first login and load it for subsequent tests — rather than driving the login form hundreds of times. This is faster and removes login as a shared point of failure.
- For email and SMS steps, use a mailbox or number the test can read programmatically (a testing inbox service, a catch-all address, or your provider's sandbox), or a provider test mode that returns a known, fixed code.
- For TOTP-based 2FA, store the shared secret for a dedicated test account and generate the current code in the test. For push-based or hardware-key MFA, use a provider bypass scoped to test environments.
- Never hard-code real credentials into a shared repo. Use dedicated test accounts and inject secrets at run time from your CI's secret store.
Test accounts and data
Use accounts created specifically for testing, in an environment where sign-up, password changes, role changes, and deletion are all safe to exercise. Keep at least one account per state you need to test:
- A standard verified user.
- An admin (or one per elevated role).
- An unverified user, to test the verification gate.
- An account with an expired or soon-to-expire session, if that path matters.
Reset or recreate these on a schedule so tests always start from a known state — stale account state is a common source of the flakiness covered here. And keep them out of any list that gets emailed or billed.
Doing it without scripting every path
The reason auth testing is painful with scripted frameworks is that you're maintaining a brittle recording of a page that changes often, plus all the token and email plumbing around it. An autonomous tool handles the common cases directly. The whole setup in Manta:
- Add a test account when you start the run. Manta asks for the starting URL and, if the app needs it, credentials — email and password, magic link, or Google sign-in work directly. Manta stores what you give it so later runs can reuse it, so use a dedicated test account, not a real user's login.
- Point it at the login page. Use the login URL (or any page that redirects there) as the start point. Manta signs in first, then explores from the authenticated state, so everything it maps is the logged-in experience.
- Describe a non-standard login in plain English. For an SSO provider, an email code, or a custom gate: "go to the login page, enter the email, click 'Send code', read the six-digit code from the inbox, and enter it." Manta follows the description instead of replaying a stored script — when the page is redesigned, there's nothing to update.
- Check what it reached. The navigation map shows the authenticated surface covered. If a whole area is missing, confirm the account's role can see it — an admin section won't appear from a regular user's session; run again with an admin account to cover it.
Two Manta-specific things to get right: run it once per role you need to cover (an admin-only area won't appear from a regular user's session), and never point it at a real customer account — it clicks things, including destructive ones. Use the dedicated test accounts and known 2FA secrets described above. For non-public deployments see testing staging environments and the private-environments guide; the end-to-end testing guide covers where auth fits in the wider plan.
Bottom line
Cover sign-up, every login method, session persistence and expiry, recovery, authorisation boundaries, and MFA — and treat the authorisation cases as security tests, not nice-to-haves. Log in for real once, then reuse the session. Use dedicated test accounts with known secrets and resettable state. And prefer describing auth steps in plain language over maintaining a selector script for a page that's redesigned twice a year.
Start free — give Manta a test account and it handles login as part of the run.