{
  "doc": {
    "id": "app/guides/authentication-testing/okta-authentication",
    "title": "Okta Authentication: Cypress Guide",
    "description": "Implement Okta authentication in Cypress end-to-end testing. Ensure secure and reliable authentication processes for Cypress testing scenarios",
    "section": "app",
    "source_path": "/llm/markdown/app/guides/authentication-testing/okta-authentication.md",
    "version": "e6988a974973e9090ce70406c38cb2b9e0eac9fa",
    "updated_at": "2026-05-15T15:50:22.536Z",
    "headings": [
      {
        "id": "app/guides/authentication-testing/okta-authentication#okta-authentication",
        "text": "Okta Authentication",
        "level": 1
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#what-youll-learn",
        "text": "What you'll learn",
        "level": 5
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#okta-developer-console-setup",
        "text": "Okta Developer Console Setup",
        "level": 2
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#setting-okta-app-credentials-in-cypress",
        "text": "Setting Okta app credentials in Cypress",
        "level": 2
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#custom-command-for-okta-authentication",
        "text": "Custom Command for Okta Authentication",
        "level": 2
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#login-with-cy-origin",
        "text": "Login with cy.origin()",
        "level": 3
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#programmatic-login",
        "text": "Programmatic Login",
        "level": 3
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#adapting-an-okta-app-for-testing",
        "text": "Adapting an Okta App for Testing",
        "level": 3
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#adapting-the-back-end",
        "text": "Adapting the back end",
        "level": 4
      },
      {
        "id": "app/guides/authentication-testing/okta-authentication#adapting-the-front-end",
        "text": "Adapting the front end",
        "level": 4
      }
    ]
  },
  "content": {
    "type": "root",
    "children": [
      {
        "type": "heading",
        "depth": 1,
        "children": [
          {
            "type": "text",
            "value": "Okta 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 test Okta authentication in Cypress"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "How to set Okta credentials in Cypress"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "How to adapt an Okta app for testing"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The scope of this guide is to demonstrate authentication solely against the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.okta.com/products/universal-directory/",
            "children": [
              {
                "type": "text",
                "value": "Okta Universal Directory"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Okta Developer Console Setup"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If not already setup, you'll need to "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://okta.com",
            "children": [
              {
                "type": "text",
                "value": "create an Okta application"
              }
            ]
          },
          {
            "type": "text",
            "value": " within the Okta Developer Console. Once the Okta application is created, the Okta Developer Console will provide a Client ID, which will be used alongside your Okta domain to "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://developer.okta.com/docs/app/sign-into-spa/react/configure-the-sdk/",
            "children": [
              {
                "type": "text",
                "value": "configure Okta SDKs"
              }
            ]
          },
          {
            "type": "text",
            "value": " as shown in the subsequent sections of this guide."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Setting Okta 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 Okta 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: {    OKTA_USERNAME: process.env.OKTA_USERNAME,    OKTA_PASSWORD: process.env.OKTA_PASSWORD,  },  expose: {    okta_domain: process.env.REACT_APP_OKTA_DOMAIN,    okta_client_id: process.env.REACT_APP_OKTA_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: {    OKTA_USERNAME: process.env.OKTA_USERNAME,    OKTA_PASSWORD: process.env.OKTA_PASSWORD,  },  expose: {    okta_domain: process.env.REACT_APP_OKTA_DOMAIN,    okta_client_id: process.env.REACT_APP_OKTA_CLIENTID,  },})"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Custom Command for Okta Authentication"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "There are two ways you can authenticate to Okta:"
          }
        ]
      },
      {
        "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 Access"
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Login with `cy.origin()`"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We'll write a custom command called `loginByOkta` to perform a login to Okta. 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 Okta origin"
                  }
                ]
              }
            ]
          },
          {
            "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/okta.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// Oktaconst loginToOkta = (username: string, password: string) => {  Cypress.log({    displayName: 'OKTA LOGIN',    message: [`🔐 Authenticating | ${username}`],    autoEnd: false,  })  cy.visit('/')  cy.origin(    Cypress.expose('okta_domain'),    { args: { username, password } },    ({ username, password }) => {      cy.get('input[name=\"identifier\"]').type(username)      cy.get('input[name=\"credentials.passcode\"]').type(password, {        log: false,      })      cy.get('[type=\"submit\"]').click()    }  )  cy.get('[data-test=\"sidenav-username\"]').should('contain', username)}// right now our custom command is light. More on this later!Cypress.Commands.add('loginByOkta', (username: string, password: string) => {  return loginToOkta(username, password)})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Now, we can use our `loginByOkta` command in the test. Below is our test to login as a user via Okta and run a few basic sanity checks."
          }
        ]
      },
      {
        "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/okta.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('Okta', function () {  beforeEach(function () {    cy.task('db:seed')    cy.env(['OKTA_USERNAME', 'OKTA_PASSWORD']).then(      ({ username, password }) => {        cy.loginByOkta(username, password)      }    )  })  it('verifies signed in user does not have a bank account', function () {    cy.get('[data-test=\"sidenav-bankaccounts\"]').click()    cy.get('[data-test=\"empty-list-header\"]').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 with everything test."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "cypress/support/commands.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "Cypress.Commands.add('loginByOkta', (username: string, password: string) => {  cy.session(    `okta-${username}`,    () => {      return loginToOkta(username, password)    },    {      validate() {        cy.visit('/')        cy.get('[data-test=\"sidenav-username\"]').should('contain', username)      },    }  )})"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Programmatic Login"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Next, we'll write a command named `loginByOktaApi` to perform a programmatic login into Okta and set an item in `localStorage` with the authenticated users details, which we'll use in our application code to verify we are authenticated under test."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In order to make sure this is enabled inside 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": ", set the `REACT_APP_OKTA_PROGRAMMATIC` environment variable to `true`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The `loginByOktaApi` 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://developer.okta.com/docs/reference/api/authn/",
                    "children": [
                      {
                        "type": "text",
                        "value": "Okta Authentication API"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " to perform the programmatic login."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Use an instance of `OktaAuth` client from the "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "https://github.com/okta/okta-auth-js",
                    "children": [
                      {
                        "type": "text",
                        "value": "Okta Auth SDK"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " to gain the `id_token` once a session token is obtained."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Finally the `oktaCypress` localStorage item is set with the `access token` and user profile."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "cypress/support/commands.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import { OktaAuth } from '@okta/okta-auth-js'// OktaCypress.Commands.add('loginByOktaApi', (username, password) => {  cy.request({    method: 'POST',    url: `https://${Cypress.expose('okta_domain')}/api/v1/authn`,    body: {      username,      password,    },  }).then(({ body }) => {    const user = body._embedded.user    const config = {      issuer: `https://${Cypress.expose('okta_domain')}/oauth2/default`,      clientId: Cypress.expose('okta_client_id'),      redirectUri: 'http://localhost:3000/implicit/callback',      scopes: ['openid', 'email', 'profile'],    }    const authClient = new OktaAuth(config)    return authClient.token      .getWithoutPrompt({ sessionToken: body.sessionToken })      .then(({ tokens }) => {        const userItem = {          token: tokens.accessToken.value,          user: {            sub: user.id,            email: user.profile.login,            given_name: user.profile.firstName,            family_name: user.profile.lastName,            preferred_username: user.profile.login,          },        }        window.localStorage.setItem('oktaCypress', JSON.stringify(userItem))        log.snapshot('after')        log.end()      })  })})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With our Okta app setup properly in Okta Developer console, necessary environment variables in place, and our `loginByOktaApi` command implemented, we will be able to authenticate with Okta while our app is under test. Below is a test to login as a user via Okta, complete the onboarding process and logout."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "auth.cy.js"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "describe('Okta', function () {  beforeEach(function () {    cy.task('db:seed')    cy.env(['OKTA_USERNAME', 'OKTA_PASSWORD']).then(      ({ username, password }) => {        cy.loginByOktaApi(username, password)      }    )  })  it('shows onboarding', function () {    cy.contains('Get Started').should('be.visible')  })})"
      },
      {
        "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/okta.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": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Adapting an Okta App for Testing"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Note"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The previous section focused on the programmatic Okta authentication practice within Cypress tests. To use this practice, it's assumed you are testing an app appropriately built or adapted to use Okta."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Unlike programmatic login, authenticating with "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/origin.md",
            "children": [
              {
                "type": "text",
                "value": "`cy.origin()`"
              }
            ]
          },
          {
            "type": "text",
            "value": " doesn't require adapting the application to work. This step is only needed if implementing programmatic login."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The following sections provides guidance on building or adapting an app to use Okta authentication."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "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": " 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/okta/okta-react",
            "children": [
              {
                "type": "text",
                "value": "Okta React SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": " for React Single Page Applications (SPA), which uses the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/okta/okta-auth-js",
            "children": [
              {
                "type": "text",
                "value": "Okta Auth SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": " underneath. The back end uses the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/okta/okta-oidc-js/tree/master/packages/jwt-verifier",
            "children": [
              {
                "type": "text",
                "value": "Okta JWT Verifier for Node.js"
              }
            ]
          },
          {
            "type": "text",
            "value": " to validate JWTs from "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://okta.com",
            "children": [
              {
                "type": "text",
                "value": "Okta"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Use the `yarn dev:okta` 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": 4,
        "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/okta/okta-oidc-js/tree/master/packages/jwt-verifier",
            "children": [
              {
                "type": "text",
                "value": "Okta JWT Verifier for Node.js"
              }
            ]
          },
          {
            "type": "text",
            "value": " and configure it using the Okta Domain and Client ID provided after "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://developer.okta.com/docs/app/sign-into-spa/react/create-okta-application/",
            "children": [
              {
                "type": "text",
                "value": "Creating an Okta application"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "backend/helpers.ts"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import OktaJwtVerifier from '@okta/jwt-verifier'dotenv.config()// Okta Validate the JWT Signatureconst oktaJwtVerifier = new OktaJwtVerifier({  issuer: `https://${process.env.REACT_APP_OKTA_DOMAIN}/oauth2/default`,  clientId: process.env.REACT_APP_OKTA_CLIENTID,  assertClaims: {    aud: 'api://default',    cid: process.env.REACT_APP_OKTA_CLIENTID,  },})"
      },
      {
        "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://okta.com",
            "children": [
              {
                "type": "text",
                "value": "Okta"
              }
            ]
          },
          {
            "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 verifyOktaToken = (req, res, next) => {  const bearerHeader = req.headers['authorization']  if (bearerHeader) {    const bearer = bearerHeader.split(' ')    const bearerToken = bearer[1]    oktaJwtVerifier      .verifyAccessToken(bearerToken, 'api://default')      .then((jwt) => {        // the token is valid        req.user = {          // @ts-ignore          sub: jwt.sub,        }        return next()      })      .catch((err) => {        // a validation failed, inspect the error        console.log('error', err)      })  } else {    res.status(401).send({      error: 'Unauthorized',    })  }}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Once this helper is defined, we can use it 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 { verifyOktaToken } from './helpers'// ...if (process.env.REACT_APP_OKTA) {  app.use(verifyOktaToken)}// routes ..."
      },
      {
        "type": "heading",
        "depth": 4,
        "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 Okta using the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/okta/okta-react",
            "children": [
              {
                "type": "text",
                "value": "Okta React SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "First, we create a `AppOkta.tsx` container, based off of the `App.tsx` component."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "`AppOkta.tsx` uses the `useOktaAuth` React Hook, replaces the Sign Up and Sign In routes with a `SecureRoute` and `LoginCallback` and wraps the component with the `withOktaAuth` higher order component (HOC)."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A `useEffect` hook is added to get the access token for the authenticated user and send an `OKTA` event with the `user` and `token` objects to work with the existing authentication layer (`authMachine.ts`). We define a route for `implicit/callback` to render the `LoginCallback` component and a `SecureRoute` for the root path."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "src/containers/AppOkta.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...import {  LoginCallback,  SecureRoute,  useOktaAuth,  withOktaAuth,} from '@okta/okta-react'// ...const AppOkta: React.FC = () => {  const { authState, oktaAuth } = useOktaAuth()  // ...  useEffect(() => {    if (authState.isAuthenticated) {      oktaAuth.getUser().then((user) => {        authService.send('OKTA', { user, token: oktaAuthState.accessToken })      })    }  }, [authState, oktaAuth])  // ...  return (    <div className={classes.root}>      // ...      {authState.matches('unauthorized') && (        <>          <Route path=\"/implicit/callback\" component={LoginCallback} />          <SecureRoute exact path=\"/\" />        </>      )}      // ...    </div>  )}export default withOktaAuth(AppOkta)"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The full "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress-realworld-app/blob/develop/src/containers/AppOkta.tsx",
            "children": [
              {
                "type": "text",
                "value": "AppOkta.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 `<Security>` component from the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/okta/okta-react",
            "children": [
              {
                "type": "text",
                "value": "Okta React SDK"
              }
            ]
          },
          {
            "type": "text",
            "value": " providing `issuer`, `clientId` from our Okta application, along with a `redirectUri` as props using the `REACT_APP_OKTA` variables are defined in our `.env`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "src/index.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...import { OktaAuth } from '@okta/okta-auth-js'import { Security } from '@okta/okta-react'import AppOkta from './containers/AppOkta'// ...const oktaAuth = new OktaAuth({  issuer: `https://${process.env.REACT_APP_OKTA_DOMAIN}/oauth2/default`,  clientId: process.env.REACT_APP_OKTA_CLIENTID,  redirectUri: window.location.origin + '/implicit/callback',})ReactDOM.render(  <Router history={history}>    <ThemeProvider theme={theme}>      {process.env.REACT_APP_OKTA ? (        <Security oktaAuth={oktaAuth}>          <AppOkta />        </Security>      ) : (        <App />      )}    </ThemeProvider>  </Router>,  document.getElementById('root'))"
      },
      {
        "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/AppOkta.tsx",
            "children": [
              {
                "type": "text",
                "value": "AppOkta.tsx component"
              }
            ]
          },
          {
            "type": "text",
            "value": " is needed to conditionally use the `oktaCypress` 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 the `withOktaAuth` higher order component only if we are not under test in Cypress. This allows our application to work with the "
          },
          {
            "type": "link",
            "title": null,
            "url": "https://okta.com",
            "children": [
              {
                "type": "text",
                "value": "Okta"
              }
            ]
          },
          {
            "type": "text",
            "value": " redirect login flow in development/production but not when under test in Cypress."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "src/containers/AppOkta.tsx"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "// initial imports ...import { LoginCallback, SecureRoute, useOktaAuth, withOktaAuth } from \"@okta/okta-react\";// ...const AppOkta: React.FC = () => {  const { authState, oktaAuth } = useOktaAuth();  // ...  // If under test in Cypress, get credentials from \"oktaCypress\" localstorage item and send event to our state management to log the user into the SPA  if (window.Cypress) {    useEffect(() => {      const okta = JSON.parse(localStorage.getItem(\"oktaCypress\")!);      authService.send(\"OKTA\", {        user: okta.user,        token: okta.token,      });    }, []);  } else {    useEffect(() => {      if (authState.isAuthenticated) {        oktaAuth.getUser().then((user) => {          authService.send(\"OKTA\", { user, token: oktaAuthState.accessToken });        });      }    }, [authState, oktaAuth]);  }  // ...  return (    <div className={classes.root}>      // ...      {authState.matches(\"unauthorized\") && (        <>          <Route path=\"/implicit/callback\" component={LoginCallback} />          <SecureRoute exact path=\"/\" />        </>      )}      // ...    </div>  );};// Conditional export wrapped with `withOktaAuth` if we are not under test in Cypresslet appOkta = window.Cypress ? AppOkta : withOktaAuth(AppOkta);export default appOkta;"
      }
    ]
  },
  "token_estimate": 2220
}