QA Icon
QAHacks
Technical / AutomationAdvanced

How do you automate MFA authentication in Cypress?

📋 Interview Context

Tool Stack:Cypress

Overview

Automating Multi-Factor Authentication (MFA) in Cypress poses a significant challenge due to its dynamic nature and the need to interact with external secrets. This topic explores robust strategies to programmatically handle MFA, ensuring efficient and secure end-to-end test execution within CI/CD pipelines.

Interview Question:

How do you automate MFA authentication in Cypress?

Expert Answer:

Automating MFA, particularly with Time-based One-Time Passwords (TOTP), in Cypress requires a programmatic approach to generate the dynamic code rather than relying on manual intervention. The most robust strategy involves securely leveraging the shared secret key used for MFA enrollment.

  1. Secure Secret Management: The MFA secret key (typically base32 encoded) is paramount. This key must be securely stored and accessed. Environment variables (CYPRESS_MFA_SECRET), populated from a secrets manager (e.g., AWS Secrets Manager, Vault) during CI/CD execution, are the best practice. Never hardcode this in source control.

  2. TOTP Generation via cy.task: Cypress test code runs in the browser, but we can execute Node.js code on the host machine using cy.task(). This is ideal for generating TOTP codes.

    • Plugin Setup (cypress/plugins/index.js): Install a library like speakeasy (npm install speakeasy).
      const speakeasy = require('speakeasy');
      module.exports = (on, config) => {
        on('task', {
          generateTotp(secret) {
            if (!secret) {
              console.error('MFA secret is missing!');
              return null;
            }
            return speakeasy.totp({
              secret: secret,
              encoding: 'base32'
            });
          }
        });
        return config;
      };
      
    • Test Usage (Custom Command):
      Cypress.Commands.add('loginWithMFA', (username, password, mfaSecret) => {
        cy.session([username, mfaSecret], () => { // Leverage Cypress.session for efficiency
          cy.visit('/login');
          cy.get('#username').type(username);
          cy.get('#password').type(password);
          cy.get('button[type="submit"]').click();
          cy.url().should('include', '/mfa'); // Wait for MFA prompt
          cy.task('generateTotp', mfaSecret || Cypress.env('MFA_SECRET'))
            .then((totpCode) => {
              if (!totpCode) {
                throw new Error('Failed to generate TOTP code.');
              }
              cy.get('#mfa-code-input').type(totpCode);
              cy.get('#mfa-submit-button').click();
              cy.url().should('not.include', '/mfa'); // Assert successful login
            });
        });
      });
      
    • In a Test File:
      it('should login successfully with MFA', () => {
        cy.loginWithMFA('testuser', 'password123', Cypress.env('MFA_SECRET'));
        cy.contains('Welcome to Dashboard').should('be.visible');
      });
      
  3. Session Persistence: After the initial successful MFA login, leverage Cypress.session() (available since Cypress 10+) or manually manage cookies/local storage using Cypress.Commands.add() to persist the authenticated state across subsequent tests. This dramatically speeds up test execution by avoiding repetitive login flows.

  4. API-Driven Authentication (Preferred for Most Tests): For the majority of E2E tests not specifically targeting the MFA UI, the most efficient method is to bypass the UI login entirely. Authenticate directly via an API call, obtain the session token (e.g., JWT, session cookie), and then inject it into Cypress using cy.setCookie() or localStorage.setItem(). This negates the need for MFA automation for most test cases.

Best Practices:

  • Isolate MFA Tests: Only a minimal, critical set of tests should exercise the full UI-driven MFA flow.
  • Robust Error Handling: Ensure the cy.task implementation handles cases where the secret might be missing or invalid.
  • Dedicated Test Accounts: Provision dedicated test accounts with known MFA secrets, rather than using production-like accounts.

Speaking Blueprint (3-Minute Verbal Response):

[The Hook] "In modern CI/CD pipelines, ensuring robust and scalable end-to-end test automation is paramount, and a frequent bottleneck we encounter is multi-factor authentication. While critical for security, MFA can significantly impede test execution velocity if not handled strategically within a framework like Cypress, ultimately impacting our engineering efficiency and time-to-market."

[The Core Execution] "My primary approach to automating MFA in Cypress revolves around programmatic generation of the One-Time Password, specifically utilizing the shared secret key. First, we establish secure storage for this MFA secret – typically accessed via environment variables or a secure vault at test runtime, ensuring it's never hardcoded in source control. Next, within our Cypress plugins/index.js file, we implement a cy.task() that leverages a Node.js library, such as speakeasy or otp-generator. This task, when invoked by the test runner, takes the securely retrieved MFA secret and dynamically generates a valid TOTP for the current time window. Our Cypress test then simply calls cy.task('generateTotp', Cypress.env('MFA_SECRET')) and, upon receiving the generated code, precisely types it into the MFA input field on the UI before proceeding with the login. For subsequent tests within the same run, we heavily leverage Cypress's built-in Cypress.session() API. This allows us to persist the authenticated session after the initial MFA login, drastically reducing redundant login steps and accelerating our test suite. Crucially, for the vast majority of our E2E tests, an API-driven login, which directly obtains a session token, is the preferred method, entirely bypassing the UI for authentication and reserving the full UI-based MFA flow for only the most critical, dedicated validation tests."

[The Punchline] "This hybrid strategy – combining programmatic TOTP generation for critical UI paths with API-driven login and intelligent session management for broader coverage – ensures that our automation framework remains highly efficient, resilient, and scalable. It allows us to thoroughly test the MFA user experience when necessary, while simultaneously maximizing test suite execution speed and maintaining a high engineering ROI by largely bypassing repetitive UI login for the bulk of our E2E coverage."

Continue Learning: Up Next