Cypress - End to End Testing - OKTA setup with MFA
The Cypress official site provides an example of OKTA Authentication Guide via programmatically login.
Why authenticate programmatically?
Typically, logging in a user within your app by authenticating via a third-party provider requires visiting login pages hosted on a different domain. Since each Cypress test is limited to visiting domains of the same origin, we can subvert visiting and testing third-party login pages by programmatically interacting with the third-party authentication API to login a user.
But for serveral cases the OKTA account requires MFA (Multi-Factor Authentication) due to company/organization security policy. Which may block us on the login process.
To pass the MFA auth in your test, we need to:
- First of all, maybe you can talk to your security team, and ask them if they can disable the MFA only for test account.
- Otherwise, set the MFA type to Security Question (See all OKTA MFA type here), then we can provide the answers directly in test cases.
- Fetch the stateToken with
UserName/Password
- Submit the MFA Answers together with stateToken
- Fetch the sessionToken
- Set sessionToken via okta lib
- Get the ID Token + Access Token
The key step is to get the sessionToken with MFA answers (see OKTA API here)
Lets see how I do the command:
Cypress.Commands.add('loginByOktaApi', (username = 'testaccount', password = 'testaccount_1234') => { /** * Visit homepage before OKTA auth to prevent postMessage error * @see https://github.com/cypress-io/cypress/issues/16310#issuecomment-1279523540 */ cy.visit('https://localhost:3000'); return cy .request({ method: 'POST', url: `https://${process.env.OKTA_DOMAIN}/api/v1/authn`, body: { username, password } }) .then(({ body }) => { const user = body._embedded.user; const stateToken = body.stateToken; const factorId = body._embedded.factors[0].id; cy.request({ method: 'POST', url: `https://${process.env.OKTA_DOMAIN}/api/v1/authn/factors/${factorId}/verify`, body: { stateToken, answer: process.env.OKTA_MFA_ANSWER } }).then(({ body }) => { const sessionToken = body.sessionToken; const config = { issuer: `https://${process.env.OKTA_DOMAIN}/oauth2/default`, clientId: process.env.OKTA_CLIENT_ID, redirectUri: 'https://localhost:3000/auth/callback', scope: ['openid', 'email', 'profile'] }; const authClient = new OktaAuth(config); return authClient.token.getWithoutPrompt({ sessionToken }).then(({ tokens }) => { window.localStorage.setItem('okta-token-storage', JSON.stringify(tokens)); }); }); }); });
You can try cy.session()
to share the same session between tests. Note that this is experimental feature until 2022 Dec, you may need to change the config file before sharing the session.
留言板
PLACE_HOLDER
PLACE_HOLDER
PLACE_HOLDER
PLACE_HOLDER