{
  "doc": {
    "id": "app/guides/authentication-testing/auth0-authentication",
    "title": "Auth0 Integration: Cypress Guide",
    "description": "Seamlessly implement Auth0 authentication with Cypress. Integrate Auth0 authentication for secure testing",
    "section": "app",
    "source_path": "/llm/markdown/app/guides/authentication-testing/auth0-authentication.md",
    "version": "fa8f60eba6ec9a949b75fe9f9f5f6591719cd01f",
    "updated_at": "2026-05-05T21:21:10.048Z",
    "headings": [
      {
        "id": "app/guides/authentication-testing/auth0-authentication#auth0-authentication",
        "text": "Auth0 Authentication",
        "level": 1
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#what-youll-learn",
        "text": "What you'll learn",
        "level": 5
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#auth0-application-setup",
        "text": "Auth0 Application Setup",
        "level": 2
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#setting-auth0-app-credentials-in-cypress",
        "text": "Setting Auth0 app credentials in Cypress",
        "level": 2
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#custom-command-for-auth0-authentication",
        "text": "Custom Command for Auth0 Authentication",
        "level": 2
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#login-with-cy-origin",
        "text": "Login with cy.origin()",
        "level": 3
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#programmatic-login",
        "text": "Programmatic Login",
        "level": 3
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#adapting-an-auth0-app-for-testing",
        "text": "Adapting an Auth0 App for Testing",
        "level": 2
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#adapting-the-back-end",
        "text": "Adapting the back end",
        "level": 3
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#adapting-the-front-end",
        "text": "Adapting the front end",
        "level": 3
      },
      {
        "id": "app/guides/authentication-testing/auth0-authentication#auth0-rate-limiting-logins",
        "text": "Auth0 Rate Limiting Logins",
        "level": 2
      }
    ]
  },
  "content": {
    "type": "root",
    "children": [
      {
        "type": "heading",
        "depth": 1,
        "children": [
          {
            "type": "text",
            "value": "Auth0 Authentication"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 5,
        "children": [
          {
            "type": "text",
            "value": "What you'll learn"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "How to authenticate with Auth0 in Cypress tests"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "How to adapt an Auth0 app for testing"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Caveats and considerations for Auth0 rate limiting"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "This guide is setup for testing against an "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": " Single Page Application using the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/universal-login/classic",
            "children": [
              {
                "type": "text",
                "value": "Classic Universal Login Experience"
              }
            ]
          },
          {
            "type": "text",
            "value": ". This configuration is recommended for a \"Test Tenant\" and/or \"Test API\" setup for automated end-to-end testing."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Auth0 Application Setup"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To get started with Auth0, an application needs to be setup within the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/get-started/auth0-overview/dashboard",
            "children": [
              {
                "type": "text",
                "value": "Auth0 Dashboard"
              }
            ]
          },
          {
            "type": "text",
            "value": " via the following steps:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": true,
        "start": 1,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Visit the "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "https://auth0.com/docs/get-started/auth0-overview/dashboard",
                    "children": [
                      {
                        "type": "text",
                        "value": "Auth0 Dashboard"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " and click the \"Create Application\" button."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Enter the desired name for your application."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Select \"Single Page Application\""
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Once your application is created, visit the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/dashboard/reference/settings-application",
            "children": [
              {
                "type": "text",
                "value": "Application Settings"
              }
            ]
          },
          {
            "type": "text",
            "value": " tab under your application, and add your local development URL and port (e.g `http://localhost:3000`) under the following sections:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Allowed Callback URLs"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Allowed Logout URLs"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Allowed Web Origins"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Allowed Origins (CORS)"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In the bottom of "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/dashboard/reference/settings-application",
            "children": [
              {
                "type": "text",
                "value": "Application Settings"
              }
            ]
          },
          {
            "type": "text",
            "value": ", click "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/dashboard/reference/settings-application#advanced-settings",
            "children": [
              {
                "type": "text",
                "value": "Show Advanced Settings"
              }
            ]
          },
          {
            "type": "text",
            "value": ", select \"Grant Types\" tab and check \"Password\" (unchecked by default)."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, click your Tenant icon (upper right avatar menu) to go to your "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/get-started/tenant-settings",
            "children": [
              {
                "type": "text",
                "value": "Tenant Settings"
              }
            ]
          },
          {
            "type": "text",
            "value": ". On the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/dashboard/reference/settings-tenant#general",
            "children": [
              {
                "type": "text",
                "value": "General"
              }
            ]
          },
          {
            "type": "text",
            "value": " tab go to the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/dashboard/reference/settings-tenant#api-authorization-settings",
            "children": [
              {
                "type": "text",
                "value": "API Authorization Settings"
              }
            ]
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Set \"Default Audience\" to the Audience URL for the Application you are testing (e.g. `https://your-api-id.auth0.com/api/v2/`)"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Set \"Default Directory\" to \"Username-Password-Authentication\""
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Refer to the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/dashboard/reference/settings-tenant",
            "children": [
              {
                "type": "text",
                "value": "Auth0 Tenant Settings documentation"
              }
            ]
          },
          {
            "type": "text",
            "value": " for additional details."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Finally, create a user in the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/connections/database#using-the-auth0-user-store",
            "children": [
              {
                "type": "text",
                "value": "Auth0 User Store"
              }
            ]
          },
          {
            "type": "text",
            "value": " for testing with Cypress. This testing-dedicated target user will be login to your application within your test specs. If required for your testing purposes, you can make as many users needed to test your specific application."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Setting Auth0 app credentials in Cypress"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To have access to test user credentials within our tests we need to configure Cypress to use the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": " environment variables set in the `.env` file."
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress.config.js"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "cypress.config.ts"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "const { defineConfig } = require('cypress')// Populate process.env with values from .env filerequire('dotenv').config()module.exports = defineConfig({  env: {    AUTH0_USERNAME: process.env.AUTH0_USERNAME,    AUTH0_PASSWORD: process.env.AUTH0_PASSWORD,  },  expose: {    auth0_domain: process.env.REACT_APP_AUTH0_DOMAIN,    auth0_audience: process.env.REACT_APP_AUTH0_AUDIENCE,    auth0_scope: process.env.REACT_APP_AUTH0_SCOPE,    auth0_client_id: process.env.REACT_APP_AUTH0_CLIENTID,  },})"
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import { defineConfig } from 'cypress'// Populate process.env with values from .env filerequire('dotenv').config()export default defineConfig({  env: {    AUTH0_USERNAME: process.env.AUTH0_USERNAME,    AUTH0_PASSWORD: process.env.AUTH0_PASSWORD,  },  expose: {    auth0_domain: process.env.REACT_APP_AUTH0_DOMAIN,    auth0_audience: process.env.REACT_APP_AUTH0_AUDIENCE,    auth0_scope: process.env.REACT_APP_AUTH0_SCOPE,    auth0_client_id: process.env.REACT_APP_AUTH0_CLIENTID,  },})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Note that `auth0_client_secret` is only needed for "
          },
          {
            "type": "link",
            "title": null,
            "url": "#Programmatic-Login",
            "children": [
              {
                "type": "text",
                "value": "programmatic login"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Custom Command for Auth0 Authentication"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "There are two ways you can authenticate to Auth0:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Login-with-cyorigin",
                    "children": [
                      {
                        "type": "text",
                        "value": "Login with `cy.origin()`"
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Programmatic-Login",
                    "children": [
                      {
                        "type": "text",
                        "value": "Programmatic Login"
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Login with "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/origin.md",
            "children": [
              {
                "type": "text",
                "value": "`cy.origin()`"
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, we'll write a custom command called `loginToAuth0` to perform a login to "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": ". This command will use "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/origin.md",
            "children": [
              {
                "type": "text",
                "value": "`cy.origin()`"
              }
            ]
          },
          {
            "type": "text",
            "value": " to"
          }
        ]
      },
      {
        "type": "list",
        "ordered": true,
        "start": 1,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Navigate to the Auth0 login"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Input user credentials"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Sign in and redirect back to the "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "https://github.com/cypress-io/cypress-realworld-app",
                    "children": [
                      {
                        "type": "text",
                        "value": "Cypress Real World App"
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Cache the results with "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/api/commands/session.md",
                    "children": [
                      {
                        "type": "text",
                        "value": "`cy.session()`"
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "cypress/support/auth-provider-commands/auth0.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "function loginViaAuth0Ui(username: string, password: string) {  // App landing page redirects to Auth0.  cy.visit('/')  // Login on Auth0.  cy.origin(    Cypress.expose('auth0_domain'),    { args: { username, password } },    ({ username, password }) => {      cy.get('input#username').type(username)      cy.get('input#password').type(password, { log: false })      cy.contains('button[value=default]', 'Continue').click()    }  )  // Ensure Auth0 has redirected us back to the RWA.  cy.url().should('equal', 'http://localhost:3000/')}Cypress.Commands.add('loginToAuth0', (username: string, password: string) => {  const log = Cypress.log({    displayName: 'AUTH0 LOGIN',    message: [`🔐 Authenticating | ${username}`],    // @ts-ignore    autoEnd: false,  })  log.snapshot('before')  loginViaAuth0Ui(username, password)  log.snapshot('after')  log.end()})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Now, we can use our `loginToAuth0` command in the test. Below is our test to login as a user via Auth0 and run a basic sanity check."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/auth0.spec.ts",
            "children": [
              {
                "type": "text",
                "value": "runnable version of this test"
              }
            ]
          },
          {
            "type": "text",
            "value": " is in the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Real World App (RWA)"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "auth.cy.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "describe('Auth0', function () {  beforeEach(function () {    cy.task('db:seed')    cy.intercept('POST', '/graphql').as('createBankAccount')    cy.env(['AUTH0_USERNAME', 'AUTH0_PASSWORD']).then(      ({ username, password }) => {        cy.loginToAuth0(username, password)      }    )    cy.visit('/')  })  it('shows onboarding', function () {    cy.contains('Get Started').should('be.visible')  })})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Lastly, we can refactor our login command to take advantage of "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/session.md",
            "children": [
              {
                "type": "text",
                "value": "`cy.session()`"
              }
            ]
          },
          {
            "type": "text",
            "value": " to store our logged in user so we don't have to reauthenticate before every test."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "cypress/support/commands.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "Cypress.Commands.add('loginToAuth0', (username: string, password: string) => {  const log = Cypress.log({    displayName: 'AUTH0 LOGIN',    message: [`🔐 Authenticating | ${username}`],    // @ts-ignore    autoEnd: false,  })  log.snapshot('before')  cy.session(    `auth0-${username}`,    () => {      loginViaAuth0Ui(username, password)    },    {      validate: () => {        // Validate presence of access token in localStorage.        cy.wrap(localStorage)          .invoke('getItem', 'authAccessToken')          .should('exist')      },    }  )  log.snapshot('after')  log.end()})"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Programmatic Login"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Below is a command to programmatically login into "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": ", using the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint",
            "children": [
              {
                "type": "text",
                "value": "/oauth/token endpoint"
              }
            ]
          },
          {
            "type": "text",
            "value": " and set an item in `localStorage` with the authenticated users details, which we will use in our application code to verify we are authenticated under test."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The `loginByAuth0Api` command will execute the following steps:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": true,
        "start": 1,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Use the "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint",
                    "children": [
                      {
                        "type": "text",
                        "value": "/oauth/token endpoint"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " to perform the programmatic login."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Finally the `auth0Cypress` `localStorage` item is set with the `access token`, `id_token` and user profile."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "cypress/support/commands.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "Cypress.Commands.add(  'loginByAuth0Api',  (username: string, password: string) => {    cy.log(`Logging in as ${username}`)    const client_id = Cypress.expose('auth0_client_id')    const audience = Cypress.expose('auth0_audience')    const scope = Cypress.expose('auth0_scope')    cy.env(['AUTH0_CLIENT_SECRET']).then(({ client_secret }) => {      cy.request({        method: 'POST',        url: `https://${Cypress.expose('auth0_domain')}/oauth/token`,        body: {          grant_type: 'password',          username,          password,          audience,          scope,          client_id,          client_secret,        },      }).then(({ body }) => {      const claims = jwt.decode(body.id_token)      const {        nickname,        name,        picture,        updated_at,        email,        email_verified,        sub,        exp,      } = claims      const item = {        body: {          ...body,          decodedToken: {            claims,            user: {              nickname,              name,              picture,              updated_at,              email,              email_verified,              sub,            },            audience,            client_id,          },        },        expiresAt: exp,      }      window.localStorage.setItem('auth0Cypress', JSON.stringify(item))      cy.visit('/')      })    })  })"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With our Auth0 app setup properly in the Auth0 Developer console, necessary environment variables in place, and our `loginByAuth0Api` command implemented, we will be able to authenticate with Auth0 while our app is under test. Below is a test to login as a user via "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": ", complete the onboarding process and logout."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "auth.cy.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "describe('Auth0', function () {  beforeEach(function () {    cy.task('db:seed')    cy.env(['AUTH0_USERNAME', 'AUTH0_PASSWORD']).then(      ({ username, password }) => {        cy.loginByAuth0Api(username, password)      }    )  })  it('shows onboarding', function () {    cy.contains('Get Started').should('be.visible')  })})"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Adapting an Auth0 App for Testing"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Note"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The previous sections focused on the recommended Auth0 authentication practice within Cypress tests. To use this practice it is assumed you are testing an app appropriately built or adapted to use Auth0."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The following sections provide guidance on building or adapting an app to use Auth0 authentication. Please note that if you are "
          },
          {
            "type": "link",
            "title": null,
            "url": "#Login-with-cyorigin",
            "children": [
              {
                "type": "text",
                "value": "logging in with `cy.origin()`"
              }
            ]
          },
          {
            "type": "text",
            "value": " and your app is already successfully integrated with Auth0, you don't need to make any further changes to your app and the remainder of this guide should be regarded as purely informational."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Real World App (RWA)"
              }
            ]
          },
          {
            "type": "text",
            "value": " is used and provides configuration and runnable code for both the React SPA and the Express back end."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The front end uses the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/auth0-react",
            "children": [
              {
                "type": "text",
                "value": "auth0-react SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": " for React Single Page Applications (SPA), which uses the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/auth0-spa-js",
            "children": [
              {
                "type": "text",
                "value": "auth0-spa-js SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": " underneath. The back end uses "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/express-jwt",
            "children": [
              {
                "type": "text",
                "value": "express-jwt"
              }
            ]
          },
          {
            "type": "text",
            "value": " to validate JWT's against "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Note"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Use the `yarn dev:auth0` command when starting the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Cypress Real World App"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Adapting the back end"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In order to validate API requests from the frontend, we install "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/express-jwt",
            "children": [
              {
                "type": "text",
                "value": "express-jwt"
              }
            ]
          },
          {
            "type": "text",
            "value": " and "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/node-jwks-rsa",
            "children": [
              {
                "type": "text",
                "value": "jwks-rsa"
              }
            ]
          },
          {
            "type": "text",
            "value": " and configure validation for JWT's from "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "backend/helpers.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import jwt from 'express-jwt'import jwksRsa from 'jwks-rsa'dotenv.config()const auth0JwtConfig = {  secret: jwksRsa.expressJwtSecret({    cache: true,    rateLimit: true,    jwksRequestsPerMinute: 5,    jwksUri: `https://${process.env.REACT_APP_AUTH0_DOMAIN}/.well-known/jwks.json`,  }),  // Validate the audience and the issuer.  audience: process.env.REACT_APP_AUTH0_AUDIENCE,  issuer: `https://${process.env.REACT_APP_AUTH0_DOMAIN}/`,  algorithms: ['RS256'],}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, we'll define an Express middleware function to be use in our routes to verify the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": " JWT sent by the front end API requests as the `Bearer` token."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "backend/helpers.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// ...export const checkJwt = jwt(auth0JwtConfig).unless({ path: ['/testData/*'] })"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Once this helper is defined, we can use globally to apply to all routes:"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "backend/app.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...import { checkJwt } from './helpers'// ...if (process.env.REACT_APP_AUTH0) {  app.use(checkJwt)}// routes ..."
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Adapting the front end"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We need to update our front end React app to allow for authentication with "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": ". As mentioned above, the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/auth0-react",
            "children": [
              {
                "type": "text",
                "value": "auth0-react SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": " for React Single Page Applications (SPA) is used."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "First, we create a `AppAuth0.tsx` container to render our application as it is authenticated with "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": ". The component is identical to the `App.tsx` component, but uses the `useAuth0` React Hook, removes the need for the Sign Up and Sign In routes and wraps the component with the `withAuthenticationRequired` higher order function (HOC)."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A `useEffect` hook is added to get the access token for the authenticated user and send an `AUTH0` event with the `user` and `token` objects to work with the existing authentication layer (`authMachine.ts`)."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "containers/AppAuth0.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...import { withAuthenticationRequired, useAuth0 } from '@auth0/auth0-react'// ...const AppAuth0 = () => {  const { isAuthenticated, user, getAccessTokenSilently } = useAuth0()  // ...  useEffect(() => {    ;(async function waitForToken() {      const token = await getAccessTokenSilently()      authService.send('AUTH0', { user, token })    })()  }, [user, getAccessTokenSilently])  // ...  const isLoggedIn =    isAuthenticated &&    (authState.matches('authorized') ||      authState.matches('refreshing') ||      authState.matches('updating'))  return <div className={classes.root}>// ...</div>}export default withAuthenticationRequired(AppAuth0)"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Note: The full "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app/blob/develop/src/containers/AppAuth0.tsx",
            "children": [
              {
                "type": "text",
                "value": "AppAuth0.tsx component"
              }
            ]
          },
          {
            "type": "text",
            "value": " is in the"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Real World App (RWA)"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, we update our entry point (`index.tsx`) to wrap our application with the `<Auth0Provider>` from the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/auth0/auth0-react",
            "children": [
              {
                "type": "text",
                "value": "auth0-react SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": " SDK providing a custom `onRedirectCallback`. We pass props for the Auth0 environment variables set in `.env` above, and render our `<AppAuth0>` component as the application."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "index.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...import AppAuth0 from \"./containers/AppAuth0\";// ..const onRedirectCallback = (appState: any) => {  history.replace((appState && appState.returnTo) || window.location.pathname);};if (process.env.REACT_APP_AUTH0) {  ReactDOM.render(    <Auth0Provider      domain={process.env.REACT_APP_AUTH0_DOMAIN!}      clientId={process.env.REACT_APP_AUTH0_CLIENTID!}      redirectUri={window.location.origin}      audience={process.env.REACT_APP_AUTH0_AUDIENCE}      scope={process.env.REACT_APP_AUTH0_SCOPE}      onRedirectCallback={onRedirectCallback}    >      <Router history={history}>        <ThemeProvider theme={theme}>          <AppAuth0 />        </ThemeProvider>      </Router>    </Auth0Provider>,    document.getElementById(\"root\")  );} else {  // render passport-local App.tsx}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "An update to our "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app/blob/develop/src/containers/AppAuth0.tsx",
            "children": [
              {
                "type": "text",
                "value": "AppAuth0.tsx component"
              }
            ]
          },
          {
            "type": "text",
            "value": " is needed to conditionally use the `auth0Cypress` `localStorage` item."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In the code below, we conditionally apply a `useEffect` block based on being under test with Cypress (using `window.Cypress`)."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In addition, we will update the export to be wrapped with `withAuthenticationRequired` if we are not under test in Cypress. This allows our application to work with the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com",
            "children": [
              {
                "type": "text",
                "value": "Auth0"
              }
            ]
          },
          {
            "type": "text",
            "value": " redirect login flow in development/production but not when under test in Cypress."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "containers/AppAuth0.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...import { withAuthenticationRequired, useAuth0 } from \"@auth0/auth0-react\";// ...const AppAuth0 = () => {  const { isAuthenticated, user, getAccessTokenSilently } = useAuth0();  // ...  useEffect(() => {      (async function waitForToken() {        const token = await getAccessTokenSilently();        authService.send(\"AUTH0\", { user, token });      })();    }, [user, getAccessTokenSilently]);  // If under test in Cypress, get credentials from \"auth0Cypress\"  // localstorage and send event to our state management to log the user into the SPA  if (window.Cypress) {    useEffect(() => {      const auth0 = JSON.parse(localStorage.getItem(\"auth0Cypress\")!);      authService.send(\"AUTH0\", {        user: auth0.body.decodedToken.user,        token: auth0.body.access_token,      });    }, []);  } else {    useEffect(() => {      (async function waitForToken() {        const token = await getAccessTokenSilently();        authService.send(\"AUTH0\", { user, token });      })();    }, [isAuthenticated, user, getAccessTokenSilently]);  }  // ...  const isLoggedIn =    isAuthenticated &&    (authState.matches(\"authorized\") ||      authState.matches(\"refreshing\") ||      authState.matches(\"updating\"));  return (    <div className={classes.root}>      // ...    </div>  );};// Conditional export wrapped with `withAuthenticationRequired`// if we aren't under test in Cypress.let appAuth0 = window.Cypress ? AppAuth0 : withAuthenticationRequired(AppAuth0);export default appAuth0"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Auth0 Rate Limiting Logins"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Be aware of the rate limit in "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/connections/database/rate-limits",
            "children": [
              {
                "type": "text",
                "value": "Auth0's documentation"
              }
            ]
          },
          {
            "type": "text",
            "value": " -"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "This limit can be reached as the size of a test suite grows along with enabling "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/features/smart-orchestration/parallelization.md",
            "children": [
              {
                "type": "text",
                "value": "parallelized runs"
              }
            ]
          },
          {
            "type": "text",
            "value": " to speed up test run duration."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If you run into this rate limit, a programmatic approach can be added to the `loginByAuth0` command to clear a blocked IP prior to the test run."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You'll need to obtain an "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/api/management/v2/tokens",
            "children": [
              {
                "type": "text",
                "value": "API token"
              }
            ]
          },
          {
            "type": "text",
            "value": " to interact with the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/api/management/v2",
            "children": [
              {
                "type": "text",
                "value": "Auth0 Management API"
              }
            ]
          },
          {
            "type": "text",
            "value": ". This token is a JSON Web Token (JWT) and it contains specific granted permissions for the API."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Add this token as environment variable `AUTH0_MGMT_API_TOKEN` to our"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app",
            "children": [
              {
                "type": "text",
                "value": "Real World App (RWA)"
              }
            ]
          },
          {
            "type": "text",
            "value": " `.env` file with your API token."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": ".env"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// ... additional keysAUTH0_MGMT_API_TOKEN = 'YOUR-MANAGEMENT-API-TOKEN'"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With this token in place, we can add interaction with the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/api/management/v2#!/Anomaly/delete_ips_by_id",
            "children": [
              {
                "type": "text",
                "value": "Auth0 Anomaly remove the blocked IP address endpoint"
              }
            ]
          },
          {
            "type": "text",
            "value": " to our `loginByAuth0Api` command. This will send a delete request to "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://auth0.com/docs/api/management/v2",
            "children": [
              {
                "type": "text",
                "value": "Auth0 Management API"
              }
            ]
          },
          {
            "type": "text",
            "value": " anomaly endpoint to unblock an IP that may become blocked during the test run."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "link",
            "title": null,
            "url": "http://icanhazip.com/",
            "children": [
              {
                "type": "text",
                "value": "icanhazip.com"
              }
            ]
          },
          {
            "type": "text",
            "value": " is a free, hosted service to find a system's current external IP address."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "cypress/support/commands.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "Cypress.Commands.add('loginByAuth0Api', (username, password) => {  // Useful when rate limited by Auth0  cy.exec('curl -4 icanhazip.com')    .its('stdout')    .then((ip) => {      cy.env(['AUTH0_MGMT_API_TOKEN']).then(({ token }) => {        cy.request({          method: 'DELETE',          url: `https://${Cypress.expose(            'auth0_domain'          )}/api/v2/anomaly/blocks/ips/${ip}`,          auth: {            bearer: token,          },        })      })    })  // ... remaining loginByAuth0Api command})"
      }
    ]
  },
  "token_estimate": 2717
}