@@ -7,31 +7,37 @@ e2eSpecific: true
7
7
8
8
## <Icon name =" graduation-cap " ></Icon > What you'll learn
9
9
10
+ - Log in to [ Okta] ( https://okta.com ) through the UI with
11
+ [ ` cy.origin() ` ] ( /api/commands/origin )
10
12
- Programmatically authenticate with [ Okta] ( https://okta.com ) via a custom
11
13
Cypress command
12
14
- Adapting your [ Okta] ( https://okta.com ) application for programmatic
13
- authentication during testing
14
-
15
- </Alert >
15
+ authentication during testing </Alert >
16
16
17
17
<Alert type =" warning " >
18
18
19
19
The scope of this guide is to demonstrate authentication solely against the
20
20
[ 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.
23
23
24
24
</Alert >
25
25
26
26
<Alert type =" success " >
27
27
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 >
29
30
30
31
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!
35
41
36
42
</Alert >
37
43
@@ -70,11 +76,116 @@ require('dotenv').config()
70
76
71
77
## Custom Command for Okta Authentication
72
78
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
+
73
180
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
75
182
authenticated users details, which we will use in our application code to verify
76
183
we are authenticated under test.
77
184
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
+
78
189
The ` loginByOktaApi ` command will execute the following steps:
79
190
80
191
1 . Use the
@@ -166,16 +277,20 @@ is in the
166
277
167
278
</Alert >
168
279
169
- ## Adapting an Okta App for Testing
280
+ ### Adapting an Okta App for Testing
170
281
171
282
<Alert type =" info " >
172
283
173
284
<strong class =" alert-header " >Note</strong >
174
285
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
177
288
appropriately built or adapted to use Okta.
178
289
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
+
179
294
The following sections provides guidance on building or adapting an app to use
180
295
Okta authentication.
181
296
@@ -202,7 +317,7 @@ Use the `yarn dev:okta` command when starting the
202
317
203
318
</Alert >
204
319
205
- ### Adapting the back end
320
+ #### Adapting the back end
206
321
207
322
In order to validate API requests from the frontend, we install
208
323
[ 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) {
281
396
// routes ...
282
397
```
283
398
284
- ### Adapting the front end
399
+ #### Adapting the front end
285
400
286
401
We need to update our front end React app to allow for authentication with
287
402
[ Okta] ( https://okta.com ) using the
0 commit comments