Skip to content

Commit ddd2c02

Browse files
AtofStrykerdebrisapron
authored andcommitted
feat: update okta login guide for realworld app (#4883)
* feat: update okta login guide for realworld app * chore: make changes to okta to have parity with cognito changes * chore: address code review comments
1 parent 94d1f2c commit ddd2c02

File tree

3 files changed

+131
-16
lines changed

3 files changed

+131
-16
lines changed

assets/img/examples/okta-origin.mp4

28.9 MB
Binary file not shown.
27 MB
Binary file not shown.

content/guides/end-to-end-testing/okta-authentication.md

Lines changed: 131 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,37 @@ e2eSpecific: true
77

88
## <Icon name="graduation-cap"></Icon> What you'll learn
99

10+
- Log in to [Okta](https://okta.com) through the UI with
11+
[`cy.origin()`](/api/commands/origin)
1012
- Programmatically authenticate with [Okta](https://okta.com) via a custom
1113
Cypress command
1214
- Adapting your [Okta](https://okta.com) application for programmatic
13-
authentication during testing
14-
15-
</Alert>
15+
authentication during testing </Alert>
1616

1717
<Alert type="warning">
1818

1919
The scope of this guide is to demonstrate authentication solely against the
2020
[Okta Universal Directory](https://www.okta.com/products/universal-directory/).
21-
Future guides will expand to include cover [Okta](https://okta.com)
22-
authentication with other identity providers.
21+
Future guides will expand to cover [Okta](https://okta.com) authentication with
22+
other identity providers.
2323

2424
</Alert>
2525

2626
<Alert type="success">
2727

28-
<strong class="alert-header">Why authenticate programmatically?</strong>
28+
<strong class="alert-header">Authenticate by visiting a different domain with
29+
[`cy.origin()`](/api/commands/origin)</strong>
2930

3031
Typically, logging in a user within your app by authenticating via a third-party
31-
provider requires visiting login pages hosted on a different domain. Since each
32-
Cypress test is limited to visiting domains of the same origin, we can subvert
33-
visiting and testing third-party login pages by programmatically interacting
34-
with the third-party authentication API to login a user.
32+
provider requires visiting a login page hosted on a different domain. Before
33+
Cypress [v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress tests were
34+
limited to visiting domains of the same origin, making programmatic login the
35+
only option for authenticating users with a third-party API. As of Cypress
36+
[v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress tests are no longer
37+
limited to visiting domains of a single origin, meaning you can easily
38+
authenticate to
39+
[Okta Universal Directory](https://www.okta.com/products/universal-directory/)
40+
via the UI!
3541

3642
</Alert>
3743

@@ -70,11 +76,116 @@ require('dotenv').config()
7076

7177
## Custom Command for Okta Authentication
7278

79+
There are two ways you can authenticate to Okta:
80+
81+
- [Login with `cy.origin()`](/guides/end-to-end-testing/okta-authentication#Login-with-cy-origin)
82+
- [Programmatic Access](/guides/end-to-end-testing/okta-authentication#Programmatic-Login)
83+
84+
### Login with [`cy.origin()`](/api/commands/origin)
85+
86+
Next, we'll write a custom command called `loginByOkta` to perform a login to
87+
[Okta](https://okta.com). This command will use
88+
[`cy.origin()`](/api/commands/origin) to
89+
90+
1. navigate to the Okta origin
91+
2. input user credentials
92+
3. sign in and redirect back to the
93+
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app)
94+
4. cache the results with [`cy.session()`](/api/commands/session)
95+
96+
```jsx
97+
// cypress/support/auth-provider-commands/okta.ts
98+
// Okta
99+
const loginToOkta = (username: string, password: string) => {
100+
Cypress.log({
101+
displayName: 'OKTA LOGIN',
102+
message: [`🔐 Authenticating | ${username}`],
103+
autoEnd: false,
104+
})
105+
106+
cy.visit('/')
107+
cy.origin(
108+
Cypress.env('okta_domain'),
109+
{ args: { username, password } },
110+
({ username, password }) => {
111+
cy.get('input[name="identifier"]').type(username)
112+
cy.get('input[name="credentials.passcode"]').type(password, {
113+
log: false,
114+
})
115+
cy.get('[type="submit"]').click()
116+
}
117+
)
118+
119+
cy.get('[data-test="sidenav-username"]').should('contain', username)
120+
}
121+
// right now our custom command is light. More on this later!
122+
Cypress.Commands.add('loginByOkta', (username: string, password: string) => {
123+
return loginToOkta(username, password)
124+
})
125+
```
126+
127+
Now, we can use our `loginByOkta` command in the test. Below is our test to
128+
login as a user via [Okta](https://okta.com) and run a few basic sanity checks.
129+
130+
<Alert type="success">
131+
132+
The
133+
[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/okta.spec.ts)
134+
is in the
135+
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app).
136+
137+
</Alert>
138+
139+
```jsx
140+
describe('Okta', function () {
141+
beforeEach(function () {
142+
cy.task('db:seed')
143+
cy.loginByOkta(Cypress.env('okta_username'), Cypress.env('okta_password'))
144+
})
145+
146+
it('verifies signed in user does not have a bank account', function () {
147+
cy.get('[data-test="sidenav-bankaccounts"]').click()
148+
cy.get('[data-test="empty-list-header"]').should('be.visible')
149+
})
150+
})
151+
```
152+
153+
<DocsVideo src="/img/examples/okta-origin.mp4"></DocsVideo>
154+
155+
Lastly, we can refactor our login command to take advantage of
156+
[`cy.session()`](/api/commands/session) to store our logged in user so we don't
157+
have to reauthenticate with everything test.
158+
159+
```jsx
160+
Cypress.Commands.add('loginByOkta', (username: string, password: string) => {
161+
cy.session(
162+
`okta-${username}`,
163+
() => {
164+
return loginToOkta(username, password)
165+
},
166+
{
167+
validate() {
168+
cy.visit('/')
169+
cy.get('[data-test="sidenav-username"]').should('contain', username)
170+
},
171+
}
172+
)
173+
})
174+
```
175+
176+
<DocsVideo src="/img/examples/okta-session-restore.mp4"></DocsVideo>
177+
178+
### Programmatic Login
179+
73180
Next, we will write a command named `loginByOktaApi` to perform a programmatic
74-
login into [Okta](https://okta.com) and set an item in localStorage with the
181+
login into [Okta](https://okta.com) and set an item in `localStorage` with the
75182
authenticated users details, which we will use in our application code to verify
76183
we are authenticated under test.
77184

185+
In order to make sure this is enabled inside the
186+
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app),
187+
Please set the `REACT_APP_OKTA_PROGRAMMATIC` environment variable to `true`.
188+
78189
The `loginByOktaApi` command will execute the following steps:
79190

80191
1. Use the
@@ -166,16 +277,20 @@ is in the
166277

167278
</Alert>
168279

169-
## Adapting an Okta App for Testing
280+
### Adapting an Okta App for Testing
170281

171282
<Alert type="info">
172283

173284
<strong class="alert-header">Note</strong>
174285

175-
The previous sections focused on the recommended Okta authentication practice
176-
within Cypress tests. To use this practice it is assumed you are testing an app
286+
The previous section focused on the programmatic Okta authentication practice
287+
within Cypress tests. To use this practice, it is assumed you are testing an app
177288
appropriately built or adapted to use Okta.
178289

290+
Unlike programmatic login, authenticating with
291+
[`cy.origin()`](/api/commands/origin) does not require adapting the application
292+
to work. This step is only needed if implementing programmatic login.
293+
179294
The following sections provides guidance on building or adapting an app to use
180295
Okta authentication.
181296

@@ -202,7 +317,7 @@ Use the `yarn dev:okta` command when starting the
202317

203318
</Alert>
204319

205-
### Adapting the back end
320+
#### Adapting the back end
206321

207322
In order to validate API requests from the frontend, we install
208323
[Okta JWT Verifier for Node.js](https://github.com/okta/okta-oidc-js/tree/master/packages/jwt-verifier)
@@ -281,7 +396,7 @@ if (process.env.REACT_APP_OKTA) {
281396
// routes ...
282397
```
283398

284-
### Adapting the front end
399+
#### Adapting the front end
285400

286401
We need to update our front end React app to allow for authentication with
287402
[Okta](https://okta.com) using the

0 commit comments

Comments
 (0)