workos 0.11.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.semaphore/semaphore.yml +2 -2
- data/Gemfile.lock +2 -2
- data/LICENSE +1 -1
- data/lib/workos.rb +2 -0
- data/lib/workos/client.rb +3 -2
- data/lib/workos/directory.rb +4 -1
- data/lib/workos/directory_user.rb +6 -1
- data/lib/workos/errors.rb +13 -2
- data/lib/workos/organizations.rb +171 -0
- data/lib/workos/portal.rb +0 -133
- data/lib/workos/profile.rb +8 -10
- data/lib/workos/profile_and_token.rb +28 -0
- data/lib/workos/sso.rb +31 -100
- data/lib/workos/types/directory_struct.rb +1 -0
- data/lib/workos/types/directory_user_struct.rb +1 -0
- data/lib/workos/version.rb +1 -1
- data/spec/lib/workos/organizations_spec.rb +191 -0
- data/spec/lib/workos/portal_spec.rb +0 -160
- data/spec/lib/workos/sso_spec.rb +41 -122
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_after.yml +12 -9
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_before.yml +8 -5
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_domain.yml +8 -8
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_limit.yml +9 -9
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_no_options.yml +23 -10
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_search.yml +8 -8
- data/spec/support/fixtures/vcr_cassettes/organization/delete.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/{sso/create_connection_with_invalid_source.yml → organization/delete_invalid.yml} +26 -12
- data/spec/support/fixtures/vcr_cassettes/sso/profile.yml +74 -0
- data/workos.gemspec +1 -1
- metadata +15 -9
- data/spec/support/fixtures/vcr_cassettes/sso/create_connection_with_valid_source.yml +0 -63
@@ -2,39 +2,6 @@
|
|
2
2
|
# typed: false
|
3
3
|
|
4
4
|
describe WorkOS::Portal do
|
5
|
-
describe '.create_organization' do
|
6
|
-
context 'with valid payload' do
|
7
|
-
it 'creates an organization' do
|
8
|
-
VCR.use_cassette 'organization/create' do
|
9
|
-
organization = described_class.create_organization(
|
10
|
-
domains: ['example.com'],
|
11
|
-
name: 'Test Organization',
|
12
|
-
)
|
13
|
-
|
14
|
-
expect(organization.id).to eq('org_01EHT88Z8J8795GZNQ4ZP1J81T')
|
15
|
-
expect(organization.name).to eq('Test Organization')
|
16
|
-
expect(organization.domains.first[:domain]).to eq('example.com')
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
context 'with an invalid payload' do
|
22
|
-
it 'returns an error' do
|
23
|
-
VCR.use_cassette 'organization/create_invalid' do
|
24
|
-
expect do
|
25
|
-
described_class.create_organization(
|
26
|
-
domains: ['example.com'],
|
27
|
-
name: 'Test Organization 2',
|
28
|
-
)
|
29
|
-
end.to raise_error(
|
30
|
-
WorkOS::APIError,
|
31
|
-
/An Organization with the domain example.com already exists/,
|
32
|
-
)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
5
|
describe '.generate_link' do
|
39
6
|
let(:organization) { 'org_01EHQMYV6MBK39QC5PZXHY59C3' }
|
40
7
|
|
@@ -100,131 +67,4 @@ describe WorkOS::Portal do
|
|
100
67
|
end
|
101
68
|
end
|
102
69
|
end
|
103
|
-
|
104
|
-
describe '.list_organizations' do
|
105
|
-
context 'with no options' do
|
106
|
-
it 'returns organizations and metadata' do
|
107
|
-
expected_metadata = {
|
108
|
-
'after' => nil,
|
109
|
-
'before' => 'before-id',
|
110
|
-
}
|
111
|
-
|
112
|
-
VCR.use_cassette 'organization/list' do
|
113
|
-
organizations = described_class.list_organizations
|
114
|
-
|
115
|
-
expect(organizations.data.size).to eq(7)
|
116
|
-
expect(organizations.list_metadata).to eq(expected_metadata)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
context 'with the before option' do
|
122
|
-
it 'forms the proper request to the API' do
|
123
|
-
request_args = [
|
124
|
-
'/organizations?before=before-id',
|
125
|
-
'Content-Type' => 'application/json'
|
126
|
-
]
|
127
|
-
|
128
|
-
expected_request = Net::HTTP::Get.new(*request_args)
|
129
|
-
|
130
|
-
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
131
|
-
and_return(expected_request)
|
132
|
-
|
133
|
-
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
134
|
-
organizations = described_class.list_organizations(
|
135
|
-
before: 'before-id',
|
136
|
-
)
|
137
|
-
|
138
|
-
expect(organizations.data.size).to eq(7)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
context 'with the after option' do
|
144
|
-
it 'forms the proper request to the API' do
|
145
|
-
request_args = [
|
146
|
-
'/organizations?after=after-id',
|
147
|
-
'Content-Type' => 'application/json'
|
148
|
-
]
|
149
|
-
|
150
|
-
expected_request = Net::HTTP::Get.new(*request_args)
|
151
|
-
|
152
|
-
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
153
|
-
and_return(expected_request)
|
154
|
-
|
155
|
-
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
156
|
-
organizations = described_class.list_organizations(after: 'after-id')
|
157
|
-
|
158
|
-
expect(organizations.data.size).to eq(7)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
context 'with the limit option' do
|
164
|
-
it 'forms the proper request to the API' do
|
165
|
-
request_args = [
|
166
|
-
'/organizations?limit=10',
|
167
|
-
'Content-Type' => 'application/json'
|
168
|
-
]
|
169
|
-
|
170
|
-
expected_request = Net::HTTP::Get.new(*request_args)
|
171
|
-
|
172
|
-
expect(Net::HTTP::Get).to receive(:new).with(*request_args).
|
173
|
-
and_return(expected_request)
|
174
|
-
|
175
|
-
VCR.use_cassette 'organization/list', match_requests_on: [:path] do
|
176
|
-
organizations = described_class.list_organizations(limit: 10)
|
177
|
-
|
178
|
-
expect(organizations.data.size).to eq(7)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
describe '.get_organization' do
|
185
|
-
context 'with a valid id' do
|
186
|
-
it 'gets the organization details' do
|
187
|
-
VCR.use_cassette('organization/get') do
|
188
|
-
organization = described_class.get_organization(
|
189
|
-
id: 'org_01EZDF20TZEJXKPSX2BJRN6TV6',
|
190
|
-
)
|
191
|
-
|
192
|
-
expect(organization.id).to eq('org_01EZDF20TZEJXKPSX2BJRN6TV6')
|
193
|
-
expect(organization.name).to eq('Foo Corp')
|
194
|
-
expect(organization.domains.first[:domain]).to eq('foo-corp.com')
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
context 'with an invalid id' do
|
200
|
-
it 'raises an error' do
|
201
|
-
VCR.use_cassette('organization/get_invalid') do
|
202
|
-
expect do
|
203
|
-
described_class.get_organization(id: 'invalid')
|
204
|
-
end.to raise_error(
|
205
|
-
WorkOS::APIError,
|
206
|
-
'Status 404, Not Found - request ID: ',
|
207
|
-
)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
describe '.update_organization' do
|
214
|
-
context 'with valid payload' do
|
215
|
-
it 'creates an organization' do
|
216
|
-
VCR.use_cassette 'organization/update' do
|
217
|
-
organization = described_class.update_organization(
|
218
|
-
organization: 'org_01F29YJ068E52HGEB8ZQGC9MJG',
|
219
|
-
domains: ['example.me'],
|
220
|
-
name: 'Test Organization',
|
221
|
-
)
|
222
|
-
|
223
|
-
expect(organization.id).to eq('org_01F29YJ068E52HGEB8ZQGC9MJG')
|
224
|
-
expect(organization.name).to eq('Test Organization')
|
225
|
-
expect(organization.domains.first[:domain]).to eq('example.me')
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
70
|
end
|
data/spec/lib/workos/sso_spec.rb
CHANGED
@@ -147,52 +147,40 @@ describe WorkOS::SSO do
|
|
147
147
|
)
|
148
148
|
end
|
149
149
|
end
|
150
|
+
end
|
150
151
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
project_id: 'workos-proj-123',
|
156
|
-
redirect_uri: 'foo.com/auth/callback',
|
157
|
-
state: {
|
158
|
-
next_page: '/dashboard/edit',
|
159
|
-
}.to_s,
|
160
|
-
}
|
161
|
-
end
|
162
|
-
it 'raises a deprecation warning' do
|
163
|
-
expect do
|
164
|
-
described_class.authorization_url(**args)
|
165
|
-
end.to output(
|
166
|
-
"[DEPRECATION] `project_id` is deprecated.
|
167
|
-
Please use `client_id` instead.\n",
|
168
|
-
).to_stderr
|
169
|
-
end
|
170
|
-
|
171
|
-
it 'returns a valid URL' do
|
172
|
-
authorization_url = described_class.authorization_url(**args)
|
173
|
-
|
174
|
-
expect(URI.parse(authorization_url)).to be_a URI
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'returns the expected hostname' do
|
178
|
-
authorization_url = described_class.authorization_url(**args)
|
152
|
+
describe '.get_profile' do
|
153
|
+
it 'returns a profile' do
|
154
|
+
VCR.use_cassette 'sso/profile' do
|
155
|
+
profile = described_class.get_profile(access_token: 'access_token')
|
179
156
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
157
|
+
expectation = {
|
158
|
+
connection_id: 'conn_01E83FVYZHY7DM4S9503JHV0R5',
|
159
|
+
connection_type: 'GoogleOAuth',
|
160
|
+
email: 'bob.loblaw@workos.com',
|
161
|
+
first_name: 'Bob',
|
162
|
+
id: 'prof_01EEJTY9SZ1R350RB7B73SNBKF',
|
163
|
+
idp_id: '116485463307139932699',
|
164
|
+
last_name: 'Loblaw',
|
165
|
+
raw_attributes: {
|
166
|
+
email: 'bob.loblaw@workos.com',
|
167
|
+
family_name: 'Loblaw',
|
168
|
+
given_name: 'Bob',
|
169
|
+
hd: 'workos.com',
|
170
|
+
id: '116485463307139932699',
|
171
|
+
locale: 'en',
|
172
|
+
name: 'Bob Loblaw',
|
173
|
+
picture: 'https://lh3.googleusercontent.com/a-/AOh14GyO2hLlgZvteDQ3Ldi3_-RteZLya0hWH7247Cam=s96-c',
|
174
|
+
verified_email: true,
|
175
|
+
},
|
176
|
+
}
|
185
177
|
|
186
|
-
expect(
|
187
|
-
'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
|
188
|
-
'&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
|
189
|
-
'edit%22%7D&domain=foo.com',
|
190
|
-
)
|
178
|
+
expect(profile.to_json).to eq(expectation)
|
191
179
|
end
|
192
180
|
end
|
193
181
|
end
|
194
182
|
|
195
|
-
describe '.
|
183
|
+
describe '.profile_and_token' do
|
196
184
|
let(:args) do
|
197
185
|
{
|
198
186
|
code: SecureRandom.hex(10),
|
@@ -225,15 +213,15 @@ describe WorkOS::SSO do
|
|
225
213
|
end
|
226
214
|
|
227
215
|
it 'includes the SDK Version header' do
|
228
|
-
described_class.
|
216
|
+
described_class.profile_and_token(**args)
|
229
217
|
|
230
218
|
expect(a_request(:post, 'https://api.workos.com/sso/token').
|
231
219
|
with(headers: headers, body: request_body)).to have_been_made
|
232
220
|
end
|
233
221
|
|
234
|
-
it 'returns a WorkOS::
|
235
|
-
|
236
|
-
expect(
|
222
|
+
it 'returns a WorkOS::ProfileAndToken' do
|
223
|
+
profile_and_token = described_class.profile_and_token(**args)
|
224
|
+
expect(profile_and_token).to be_a(WorkOS::ProfileAndToken)
|
237
225
|
|
238
226
|
expectation = {
|
239
227
|
connection_id: 'conn_01EMH8WAK20T42N2NBMNBCYHAG',
|
@@ -252,7 +240,8 @@ describe WorkOS::SSO do
|
|
252
240
|
},
|
253
241
|
}
|
254
242
|
|
255
|
-
expect(
|
243
|
+
expect(profile_and_token.access_token).to eq('01DVX6QBS3EG6FHY2ESAA5Q65X')
|
244
|
+
expect(profile_and_token.profile.to_json).to eq(expectation)
|
256
245
|
end
|
257
246
|
end
|
258
247
|
|
@@ -263,16 +252,16 @@ describe WorkOS::SSO do
|
|
263
252
|
to_return(
|
264
253
|
headers: { 'X-Request-ID' => 'request-id' },
|
265
254
|
status: 422,
|
266
|
-
body: { "
|
255
|
+
body: { "error": 'some error', "error_description": 'some error description' }.to_json,
|
267
256
|
)
|
268
257
|
end
|
269
258
|
|
270
259
|
it 'raises an exception with request ID' do
|
271
260
|
expect do
|
272
|
-
described_class.
|
261
|
+
described_class.profile_and_token(**args)
|
273
262
|
end.to raise_error(
|
274
263
|
WorkOS::APIError,
|
275
|
-
'some error
|
264
|
+
'error: some error, error_description: some error description - request ID: request-id',
|
276
265
|
)
|
277
266
|
end
|
278
267
|
end
|
@@ -282,97 +271,27 @@ describe WorkOS::SSO do
|
|
282
271
|
stub_request(:post, 'https://api.workos.com/sso/token').
|
283
272
|
with(body: request_body).
|
284
273
|
to_return(
|
285
|
-
status:
|
274
|
+
status: 400,
|
286
275
|
headers: { 'X-Request-ID' => 'request-id' },
|
287
276
|
body: {
|
288
|
-
|
289
|
-
|
277
|
+
"error": 'invalid_grant',
|
278
|
+
"error_description": "The code '01DVX3C5Z367SFHR8QNDMK7V24' has expired or is invalid.",
|
290
279
|
}.to_json,
|
291
280
|
)
|
292
281
|
end
|
293
282
|
|
294
283
|
it 'raises an exception' do
|
295
284
|
expect do
|
296
|
-
described_class.
|
285
|
+
described_class.profile_and_token(**args)
|
297
286
|
end.to raise_error(
|
298
287
|
WorkOS::APIError,
|
299
|
-
"The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
|
288
|
+
"error: invalid_grant, error_description: The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
|
300
289
|
' has expired or is invalid. - request ID: request-id',
|
301
290
|
)
|
302
291
|
end
|
303
292
|
end
|
304
293
|
end
|
305
294
|
|
306
|
-
describe '.create_connection' do
|
307
|
-
context 'with a valid source' do
|
308
|
-
it 'creates a connection' do
|
309
|
-
VCR.use_cassette('sso/create_connection_with_valid_source') do
|
310
|
-
connection = WorkOS::SSO.create_connection(
|
311
|
-
source: 'draft_conn_01E6PK87QP6NQ29RRX0G100YGV',
|
312
|
-
)
|
313
|
-
|
314
|
-
expect(connection.id).to eq('conn_01E4F9T2YWZFD218DN04KVFDSY')
|
315
|
-
expect(connection.connection_type).to eq('GoogleOAuth')
|
316
|
-
expect(connection.name).to eq('Foo Corp')
|
317
|
-
expect(connection.domains.first[:domain]).to eq('example.com')
|
318
|
-
expect(connection.organization_id).to eq('12345')
|
319
|
-
expect(connection.state).to eq('active')
|
320
|
-
expect(connection.status).to eq('linked')
|
321
|
-
end
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
context 'with an invalid source' do
|
326
|
-
it 'raises an error' do
|
327
|
-
VCR.use_cassette('sso/create_connection_with_invalid_source') do
|
328
|
-
expect do
|
329
|
-
WorkOS::SSO.create_connection(source: 'invalid')
|
330
|
-
end.to raise_error(
|
331
|
-
WorkOS::APIError,
|
332
|
-
'Status 404, Not Found - request ID: ',
|
333
|
-
)
|
334
|
-
end
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
describe '.promote_draft_connection' do
|
340
|
-
let(:token) { 'draft_conn_id' }
|
341
|
-
let(:client_id) { 'proj_0239u590h' }
|
342
|
-
|
343
|
-
context 'with a valid request' do
|
344
|
-
before do
|
345
|
-
stub_request(
|
346
|
-
:post,
|
347
|
-
"https://api.workos.com/draft_connections/#{token}/activate",
|
348
|
-
).to_return(status: 200)
|
349
|
-
end
|
350
|
-
it 'returns true' do
|
351
|
-
response = described_class.promote_draft_connection(
|
352
|
-
token: token,
|
353
|
-
)
|
354
|
-
|
355
|
-
expect(response).to be(true)
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
context 'with an invalid request' do
|
360
|
-
before do
|
361
|
-
stub_request(
|
362
|
-
:post,
|
363
|
-
"https://api.workos.com/draft_connections/#{token}/activate",
|
364
|
-
).to_return(status: 403)
|
365
|
-
end
|
366
|
-
it 'returns true' do
|
367
|
-
response = described_class.promote_draft_connection(
|
368
|
-
token: token,
|
369
|
-
)
|
370
|
-
|
371
|
-
expect(response).to be(false)
|
372
|
-
end
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
295
|
describe '.list_connections' do
|
377
296
|
context 'with no options' do
|
378
297
|
it 'returns connections and metadata' do
|
@@ -14,7 +14,7 @@ http_interactions:
|
|
14
14
|
Accept:
|
15
15
|
- "*/*"
|
16
16
|
User-Agent:
|
17
|
-
- WorkOS; ruby/
|
17
|
+
- WorkOS; ruby/3.0.1; x86_64-darwin19; v1.2.1
|
18
18
|
Authorization:
|
19
19
|
- Bearer <API_KEY>
|
20
20
|
response:
|
@@ -53,20 +53,23 @@ http_interactions:
|
|
53
53
|
X-Xss-Protection:
|
54
54
|
- '0'
|
55
55
|
X-Request-Id:
|
56
|
-
-
|
56
|
+
- 167e0fa2-cee2-4834-a0aa-4f68fd0a3796
|
57
57
|
Content-Type:
|
58
58
|
- application/json; charset=utf-8
|
59
|
+
Content-Length:
|
60
|
+
- '784'
|
59
61
|
Etag:
|
60
|
-
- W/"
|
62
|
+
- W/"310-fBrsCTIA95j4JLo4UR8X2zBThYQ"
|
61
63
|
Date:
|
62
|
-
-
|
63
|
-
Transfer-Encoding:
|
64
|
-
- chunked
|
64
|
+
- Mon, 07 Jun 2021 17:55:30 GMT
|
65
65
|
Via:
|
66
66
|
- 1.1 vegur
|
67
67
|
body:
|
68
|
-
encoding:
|
69
|
-
string: '{"object":"list","listMetadata":{"before":
|
68
|
+
encoding: UTF-8
|
69
|
+
string: '{"object":"list","listMetadata":{"before":null,"after":null},"data":[{"object":"directory","id":"directory_01F7796W20KW0CXEQQEYENT0ZC","organization_id":"org_01EZDF20TZEJXKPSX2BJRN6TV6","name":"Bamboo
|
70
|
+
Test","external_key":"rPzV4pdpbaUiKsc6","type":"bamboohr","state":"unlinked","domain":"foo-corp.com"},{"object":"directory","id":"directory_01F5ZY7XVQZ3DRYEZTH1EPA8BS","organization_id":"org_01EZDF20TZEJXKPSX2BJRN6TV6","name":"Foo
|
71
|
+
Corp","external_key":"qV4eyK99QGUaYYa0","type":"okta scim v2.0","state":"linked","domain":"foo-corp.com"},{"object":"directory","id":"directory_01F5XHH1QHX6C2F0Z6WG9YPGCJ","organization_id":"org_01F29YJ068E52HGEB8ZQGC9MJG","name":"Example
|
72
|
+
Azure SCIM","external_key":"YDKJvbWHKKg66cSk","type":"azure scim v2.0","state":"linked","domain":"example.com"}]}'
|
70
73
|
http_version:
|
71
|
-
recorded_at:
|
74
|
+
recorded_at: Mon, 07 Jun 2021 17:55:30 GMT
|
72
75
|
recorded_with: VCR 5.0.0
|
@@ -14,7 +14,7 @@ http_interactions:
|
|
14
14
|
Accept:
|
15
15
|
- "*/*"
|
16
16
|
User-Agent:
|
17
|
-
- WorkOS; ruby/
|
17
|
+
- WorkOS; ruby/3.0.1; x86_64-darwin19; v1.2.1
|
18
18
|
Authorization:
|
19
19
|
- Bearer <API_KEY>
|
20
20
|
response:
|
@@ -53,7 +53,7 @@ http_interactions:
|
|
53
53
|
X-Xss-Protection:
|
54
54
|
- '0'
|
55
55
|
X-Request-Id:
|
56
|
-
-
|
56
|
+
- d5e27591-7a56-468c-bffe-3a035f3bf26c
|
57
57
|
Content-Type:
|
58
58
|
- application/json; charset=utf-8
|
59
59
|
Content-Length:
|
@@ -61,12 +61,15 @@ http_interactions:
|
|
61
61
|
Etag:
|
62
62
|
- W/"47-5KOnfOsRy36pnaPjBxvaf6LRiGc"
|
63
63
|
Date:
|
64
|
-
-
|
64
|
+
- Mon, 07 Jun 2021 17:55:30 GMT
|
65
65
|
Via:
|
66
66
|
- 1.1 vegur
|
67
67
|
body:
|
68
68
|
encoding: UTF-8
|
69
|
-
string: '{"object":"list","listMetadata":{"before":
|
69
|
+
string: '{"object":"list","listMetadata":{"before":null,"after":null},"data":[{"object":"directory","id":"directory_01F7796W20KW0CXEQQEYENT0ZC","organization_id":"org_01EZDF20TZEJXKPSX2BJRN6TV6","name":"Bamboo
|
70
|
+
Test","external_key":"rPzV4pdpbaUiKsc6","type":"bamboohr","state":"unlinked","domain":"foo-corp.com"},{"object":"directory","id":"directory_01F5ZY7XVQZ3DRYEZTH1EPA8BS","organization_id":"org_01EZDF20TZEJXKPSX2BJRN6TV6","name":"Foo
|
71
|
+
Corp","external_key":"qV4eyK99QGUaYYa0","type":"okta scim v2.0","state":"linked","domain":"foo-corp.com"},{"object":"directory","id":"directory_01F5XHH1QHX6C2F0Z6WG9YPGCJ","organization_id":"org_01F29YJ068E52HGEB8ZQGC9MJG","name":"Example
|
72
|
+
Azure SCIM","external_key":"YDKJvbWHKKg66cSk","type":"azure scim v2.0","state":"linked","domain":"example.com"}]}'
|
70
73
|
http_version:
|
71
|
-
recorded_at:
|
74
|
+
recorded_at: Mon, 07 Jun 2021 17:55:30 GMT
|
72
75
|
recorded_with: VCR 5.0.0
|