workos 5.21.0 → 5.23.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/Gemfile.lock +1 -1
- data/lib/workos/organization.rb +3 -0
- data/lib/workos/organizations.rb +8 -0
- data/lib/workos/session.rb +1 -0
- data/lib/workos/sso.rb +3 -24
- data/lib/workos/user_management.rb +17 -14
- data/lib/workos/version.rb +1 -1
- data/spec/lib/workos/organizations_spec.rb +52 -0
- data/spec/lib/workos/session_spec.rb +38 -0
- data/spec/lib/workos/sso_spec.rb +87 -4
- data/spec/lib/workos/user_management_spec.rb +122 -0
- data/spec/support/fixtures/vcr_cassettes/organization/create_with_external_id.yml +83 -0
- data/spec/support/fixtures/vcr_cassettes/organization/update_with_external_id.yml +78 -0
- data/spec/support/fixtures/vcr_cassettes/organization/update_with_external_id_null.yml +78 -0
- data/spec/support/fixtures/vcr_cassettes/user_management/create_user_with_external_id.yml +77 -0
- data/spec/support/fixtures/vcr_cassettes/user_management/update_user_external_id_null.yml +77 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 840052dd55f646d6ae09f2c0e0a4c91a6686d0f4fcb3b9da66b13fa3e4f835eb
|
4
|
+
data.tar.gz: cb5807f1a8b0b1fe28f21e5c8cfa84fd3c75e68bf7e743f9f95a5ac1787efd55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fccea79a69343e4deeb1f25e076dfc19febbd5a540bd0e9e55ad6f4859ef3332a300e1f023e74c8bad7c16fe1c2b7266eb8bc5dfd600ddb0d40e036ff48d739f
|
7
|
+
data.tar.gz: b49a2c19e2360811203f8b07806a198bd7b9307dc654b72fb266311ff7fbf881b0cb142159a67144c25057d340e3d4fdd11bba1fc42e509bf05fcf427dcd9a48
|
data/Gemfile.lock
CHANGED
data/lib/workos/organization.rb
CHANGED
@@ -12,6 +12,7 @@ module WorkOS
|
|
12
12
|
:domains,
|
13
13
|
:stripe_customer_id,
|
14
14
|
:name,
|
15
|
+
:external_id,
|
15
16
|
:allow_profiles_outside_organization,
|
16
17
|
:created_at,
|
17
18
|
:updated_at,
|
@@ -22,6 +23,7 @@ module WorkOS
|
|
22
23
|
|
23
24
|
@id = hash[:id]
|
24
25
|
@name = hash[:name]
|
26
|
+
@external_id = hash[:external_id]
|
25
27
|
@allow_profiles_outside_organization = hash[:allow_profiles_outside_organization]
|
26
28
|
@domains = hash[:domains]
|
27
29
|
@stripe_customer_id = hash[:stripe_customer_id]
|
@@ -33,6 +35,7 @@ module WorkOS
|
|
33
35
|
{
|
34
36
|
id: id,
|
35
37
|
name: name,
|
38
|
+
external_id: external_id,
|
36
39
|
allow_profiles_outside_organization: allow_profiles_outside_organization,
|
37
40
|
domains: domains,
|
38
41
|
stripe_customer_id: stripe_customer_id,
|
data/lib/workos/organizations.rb
CHANGED
@@ -75,6 +75,7 @@ module WorkOS
|
|
75
75
|
# @option domain_data [String] domain The domain that belongs to the organization.
|
76
76
|
# @option domain_data [String] state The state of the domain. "verified" or "pending"
|
77
77
|
# @param [String] name A unique, descriptive name for the organization
|
78
|
+
# @param [String] external_id The organization's external ID.
|
78
79
|
# @param [String] idempotency_key An idempotency key
|
79
80
|
# @param [Boolean, nil] allow_profiles_outside_organization Whether Connections
|
80
81
|
# within the Organization allow profiles that are outside of the Organization's configured User Email Domains.
|
@@ -85,11 +86,13 @@ module WorkOS
|
|
85
86
|
domain_data: nil,
|
86
87
|
domains: nil,
|
87
88
|
name:,
|
89
|
+
external_id: nil,
|
88
90
|
allow_profiles_outside_organization: nil,
|
89
91
|
idempotency_key: nil
|
90
92
|
)
|
91
93
|
body = { name: name }
|
92
94
|
body[:domain_data] = domain_data if domain_data
|
95
|
+
body[:external_id] = external_id if external_id
|
93
96
|
|
94
97
|
if domains
|
95
98
|
warn_deprecation '`domains` is deprecated. Use `domain_data` instead.'
|
@@ -123,22 +126,26 @@ module WorkOS
|
|
123
126
|
# @option domain_data [String] state The state of the domain. "verified" or "pending"
|
124
127
|
# @param [String] stripe_customer_id The Stripe customer ID associated with this organization.
|
125
128
|
# @param [String] name A unique, descriptive name for the organization
|
129
|
+
# @param [String] external_id The organization's external ID.
|
126
130
|
# @param [Boolean, nil] allow_profiles_outside_organization Whether Connections
|
127
131
|
# within the Organization allow profiles that are outside of the Organization's configured User Email Domains.
|
128
132
|
# Deprecated: If you need to allow sign-ins from any email domain, contact suppport@workos.com.
|
129
133
|
# @param [Array<String>] domains List of domains that belong to the organization.
|
130
134
|
# Deprecated: Use domain_data instead.
|
135
|
+
# rubocop:disable Metrics/ParameterLists
|
131
136
|
def update_organization(
|
132
137
|
organization:,
|
133
138
|
stripe_customer_id: nil,
|
134
139
|
domain_data: nil,
|
135
140
|
domains: nil,
|
136
141
|
name: nil,
|
142
|
+
external_id: :not_set,
|
137
143
|
allow_profiles_outside_organization: nil
|
138
144
|
)
|
139
145
|
body = { name: name }
|
140
146
|
body[:domain_data] = domain_data if domain_data
|
141
147
|
body[:stripe_customer_id] = stripe_customer_id if stripe_customer_id
|
148
|
+
body[:external_id] = external_id if external_id != :not_set
|
142
149
|
|
143
150
|
if domains
|
144
151
|
warn_deprecation '`domains` is deprecated. Use `domain_data` instead.'
|
@@ -162,6 +169,7 @@ module WorkOS
|
|
162
169
|
|
163
170
|
WorkOS::Organization.new(response.body)
|
164
171
|
end
|
172
|
+
# rubocop:enable Metrics/ParameterLists
|
165
173
|
|
166
174
|
# Delete an Organization
|
167
175
|
#
|
data/lib/workos/session.rb
CHANGED
data/lib/workos/sso.rb
CHANGED
@@ -120,8 +120,9 @@ module WorkOS
|
|
120
120
|
code: code,
|
121
121
|
}
|
122
122
|
|
123
|
-
response =
|
124
|
-
|
123
|
+
response = execute_request(
|
124
|
+
request: post_request(path: '/sso/token', body: body),
|
125
|
+
)
|
125
126
|
|
126
127
|
WorkOS::ProfileAndToken.new(response.body)
|
127
128
|
end
|
@@ -229,28 +230,6 @@ module WorkOS
|
|
229
230
|
raise ArgumentError, "#{provider} is not a valid value." \
|
230
231
|
" `provider` must be in #{PROVIDERS}"
|
231
232
|
end
|
232
|
-
|
233
|
-
def check_and_raise_profile_and_token_error(response:)
|
234
|
-
begin
|
235
|
-
body = JSON.parse(response.body)
|
236
|
-
return if body['access_token'] && body['profile']
|
237
|
-
|
238
|
-
message = body['message']
|
239
|
-
error = body['error']
|
240
|
-
error_description = body['error_description']
|
241
|
-
request_id = response['x-request-id']
|
242
|
-
rescue StandardError
|
243
|
-
message = 'Something went wrong'
|
244
|
-
end
|
245
|
-
|
246
|
-
raise APIError.new(
|
247
|
-
message: message,
|
248
|
-
error: error,
|
249
|
-
error_description: error_description,
|
250
|
-
http_status: nil,
|
251
|
-
request_id: request_id,
|
252
|
-
)
|
253
|
-
end
|
254
233
|
end
|
255
234
|
end
|
256
235
|
end
|
@@ -182,6 +182,7 @@ module WorkOS
|
|
182
182
|
# @param [String] first_name The user's first name.
|
183
183
|
# @param [String] last_name The user's last name.
|
184
184
|
# @param [Boolean] email_verified Whether the user's email address was previously verified.
|
185
|
+
# @param [String] external_id The user's external ID.
|
185
186
|
# @param [String] password_hash The user's hashed password.
|
186
187
|
# @option [String] password_hash_type The algorithm originally used to hash the password.
|
187
188
|
#
|
@@ -193,6 +194,7 @@ module WorkOS
|
|
193
194
|
first_name: nil,
|
194
195
|
last_name: nil,
|
195
196
|
email_verified: nil,
|
197
|
+
external_id: nil,
|
196
198
|
password_hash: nil,
|
197
199
|
password_hash_type: nil
|
198
200
|
)
|
@@ -204,9 +206,10 @@ module WorkOS
|
|
204
206
|
first_name: first_name,
|
205
207
|
last_name: last_name,
|
206
208
|
email_verified: email_verified,
|
209
|
+
external_id: external_id,
|
207
210
|
password_hash: password_hash,
|
208
211
|
password_hash_type: password_hash_type,
|
209
|
-
},
|
212
|
+
}.compact,
|
210
213
|
auth: true,
|
211
214
|
)
|
212
215
|
|
@@ -231,14 +234,14 @@ module WorkOS
|
|
231
234
|
# @return [WorkOS::User]
|
232
235
|
def update_user(
|
233
236
|
id:,
|
234
|
-
email:
|
235
|
-
first_name:
|
236
|
-
last_name:
|
237
|
-
email_verified:
|
238
|
-
external_id:
|
239
|
-
password:
|
240
|
-
password_hash:
|
241
|
-
password_hash_type:
|
237
|
+
email: :not_set,
|
238
|
+
first_name: :not_set,
|
239
|
+
last_name: :not_set,
|
240
|
+
email_verified: :not_set,
|
241
|
+
external_id: :not_set,
|
242
|
+
password: :not_set,
|
243
|
+
password_hash: :not_set,
|
244
|
+
password_hash_type: :not_set
|
242
245
|
)
|
243
246
|
request = put_request(
|
244
247
|
path: "/user_management/users/#{id}",
|
@@ -251,7 +254,7 @@ module WorkOS
|
|
251
254
|
password: password,
|
252
255
|
password_hash: password_hash,
|
253
256
|
password_hash_type: password_hash_type,
|
254
|
-
},
|
257
|
+
}.reject { |_, v| v == :not_set },
|
255
258
|
auth: true,
|
256
259
|
)
|
257
260
|
|
@@ -643,7 +646,7 @@ module WorkOS
|
|
643
646
|
body: {
|
644
647
|
email: email,
|
645
648
|
invitation_token: invitation_token,
|
646
|
-
},
|
649
|
+
}.compact,
|
647
650
|
auth: true,
|
648
651
|
),
|
649
652
|
)
|
@@ -697,7 +700,7 @@ module WorkOS
|
|
697
700
|
totp_issuer: totp_issuer,
|
698
701
|
totp_user: totp_user,
|
699
702
|
totp_secret: totp_secret,
|
700
|
-
},
|
703
|
+
}.compact,
|
701
704
|
auth: true,
|
702
705
|
),
|
703
706
|
)
|
@@ -928,7 +931,7 @@ module WorkOS
|
|
928
931
|
user_id: user_id,
|
929
932
|
organization_id: organization_id,
|
930
933
|
role_slug: role_slug,
|
931
|
-
},
|
934
|
+
}.compact,
|
932
935
|
auth: true,
|
933
936
|
)
|
934
937
|
|
@@ -1093,7 +1096,7 @@ module WorkOS
|
|
1093
1096
|
expires_in_days: expires_in_days,
|
1094
1097
|
inviter_user_id: inviter_user_id,
|
1095
1098
|
role_slug: role_slug,
|
1096
|
-
},
|
1099
|
+
}.compact,
|
1097
1100
|
auth: true,
|
1098
1101
|
),
|
1099
1102
|
)
|
data/lib/workos/version.rb
CHANGED
@@ -33,6 +33,21 @@ describe WorkOS::Organizations do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
context 'with external_id' do
|
37
|
+
it 'creates an organization with external_id' do
|
38
|
+
VCR.use_cassette 'organization/create_with_external_id' do
|
39
|
+
organization = described_class.create_organization(
|
40
|
+
name: 'Test Organization with External ID',
|
41
|
+
external_id: 'ext_org_123',
|
42
|
+
)
|
43
|
+
|
44
|
+
expect(organization.id).to start_with('org_')
|
45
|
+
expect(organization.name).to eq('Test Organization with External ID')
|
46
|
+
expect(organization.external_id).to eq('ext_org_123')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
36
51
|
context 'with domains' do
|
37
52
|
it 'creates an organization and warns' do
|
38
53
|
VCR.use_cassette 'organization/create_with_domains' do
|
@@ -310,6 +325,43 @@ describe WorkOS::Organizations do
|
|
310
325
|
end
|
311
326
|
end
|
312
327
|
end
|
328
|
+
context 'with an external_id' do
|
329
|
+
it 'updates the organization' do
|
330
|
+
VCR.use_cassette 'organization/update_with_external_id' do
|
331
|
+
organization = described_class.update_organization(
|
332
|
+
organization: 'org_01K0SQV0S6EPWK2ZDEFD1CP1JC',
|
333
|
+
name: 'Test Organization',
|
334
|
+
external_id: 'ext_org_456',
|
335
|
+
)
|
336
|
+
|
337
|
+
expect(organization.id).to eq('org_01K0SQV0S6EPWK2ZDEFD1CP1JC')
|
338
|
+
expect(organization.name).to eq('Test Organization')
|
339
|
+
expect(organization.external_id).to eq('ext_org_456')
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
context 'can set external_id to null explicitly' do
|
345
|
+
it 'includes external_id null in request body' do
|
346
|
+
original_method = described_class.method(:put_request)
|
347
|
+
allow(described_class).to receive(:put_request) do |kwargs|
|
348
|
+
original_method.call(**kwargs)
|
349
|
+
end
|
350
|
+
|
351
|
+
VCR.use_cassette 'organization/update_with_external_id_null' do
|
352
|
+
described_class.update_organization(
|
353
|
+
organization: 'org_01K0SQV0S6EPWK2ZDEFD1CP1JC',
|
354
|
+
name: 'Test Organization',
|
355
|
+
external_id: nil,
|
356
|
+
)
|
357
|
+
end
|
358
|
+
|
359
|
+
# Verify the spy captured the right call
|
360
|
+
expect(described_class).to have_received(:put_request).with(
|
361
|
+
hash_including(body: hash_including(external_id: nil)),
|
362
|
+
)
|
363
|
+
end
|
364
|
+
end
|
313
365
|
end
|
314
366
|
|
315
367
|
describe '.delete_organization' do
|
@@ -174,6 +174,7 @@ describe WorkOS::Session do
|
|
174
174
|
organization_id: 'org_id',
|
175
175
|
role: 'role',
|
176
176
|
permissions: ['read'],
|
177
|
+
feature_flags: nil,
|
177
178
|
entitlements: nil,
|
178
179
|
user: 'user',
|
179
180
|
impersonator: 'impersonator',
|
@@ -209,6 +210,43 @@ describe WorkOS::Session do
|
|
209
210
|
role: 'role',
|
210
211
|
permissions: ['read'],
|
211
212
|
entitlements: ['billing'],
|
213
|
+
feature_flags: nil,
|
214
|
+
user: 'user',
|
215
|
+
impersonator: 'impersonator',
|
216
|
+
reason: nil,
|
217
|
+
})
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe 'with feature flags' do
|
222
|
+
let(:payload) do
|
223
|
+
{
|
224
|
+
sid: 'session_id',
|
225
|
+
org_id: 'org_id',
|
226
|
+
role: 'role',
|
227
|
+
permissions: ['read'],
|
228
|
+
feature_flags: ['new_feature_enabled'],
|
229
|
+
exp: Time.now.to_i + 3600,
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'includes feature flags in the result' do
|
234
|
+
session = WorkOS::Session.new(
|
235
|
+
user_management: user_management,
|
236
|
+
client_id: client_id,
|
237
|
+
session_data: session_data,
|
238
|
+
cookie_password: cookie_password,
|
239
|
+
)
|
240
|
+
allow_any_instance_of(JWT::Decode).to receive(:verify_signature).and_return(true)
|
241
|
+
result = session.authenticate
|
242
|
+
expect(result).to eq({
|
243
|
+
authenticated: true,
|
244
|
+
session_id: 'session_id',
|
245
|
+
organization_id: 'org_id',
|
246
|
+
role: 'role',
|
247
|
+
permissions: ['read'],
|
248
|
+
entitlements: nil,
|
249
|
+
feature_flags: ['new_feature_enabled'],
|
212
250
|
user: 'user',
|
213
251
|
impersonator: 'impersonator',
|
214
252
|
reason: nil,
|
data/spec/lib/workos/sso_spec.rb
CHANGED
@@ -416,10 +416,73 @@ describe WorkOS::SSO do
|
|
416
416
|
expect do
|
417
417
|
described_class.profile_and_token(**args)
|
418
418
|
end.to raise_error(
|
419
|
-
WorkOS::
|
420
|
-
'
|
419
|
+
WorkOS::UnprocessableEntityError,
|
420
|
+
'Status 422, some error - request ID: request-id',
|
421
421
|
)
|
422
422
|
end
|
423
|
+
|
424
|
+
it 'raises an exception with proper error object attributes' do
|
425
|
+
expect do
|
426
|
+
described_class.profile_and_token(**args)
|
427
|
+
end.to raise_error(WorkOS::UnprocessableEntityError)
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'includes proper error attributes' do
|
431
|
+
error = begin
|
432
|
+
described_class.profile_and_token(**args)
|
433
|
+
rescue WorkOS::UnprocessableEntityError => e
|
434
|
+
e
|
435
|
+
end
|
436
|
+
|
437
|
+
expect(error.http_status).to eq(422)
|
438
|
+
expect(error.request_id).to eq('request-id')
|
439
|
+
expect(error.error).to eq('some error')
|
440
|
+
expect(error.message).to include('some error')
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
context 'with detailed field validation errors' do
|
445
|
+
before do
|
446
|
+
stub_request(:post, 'https://api.workos.com/sso/token').
|
447
|
+
with(headers: headers, body: request_body).
|
448
|
+
to_return(
|
449
|
+
headers: { 'X-Request-ID' => 'request-id' },
|
450
|
+
status: 422,
|
451
|
+
body: {
|
452
|
+
"message": 'Validation failed',
|
453
|
+
"code": 'invalid_request_parameters',
|
454
|
+
"errors": [
|
455
|
+
{
|
456
|
+
"field": 'code',
|
457
|
+
"code": 'missing_required_parameter',
|
458
|
+
"message": 'The code parameter is required',
|
459
|
+
}
|
460
|
+
],
|
461
|
+
}.to_json,
|
462
|
+
)
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'raises an exception with detailed field errors' do
|
466
|
+
expect do
|
467
|
+
described_class.profile_and_token(**args)
|
468
|
+
end.to raise_error(WorkOS::UnprocessableEntityError)
|
469
|
+
end
|
470
|
+
|
471
|
+
it 'includes detailed field error attributes' do
|
472
|
+
error = begin
|
473
|
+
described_class.profile_and_token(**args)
|
474
|
+
rescue WorkOS::UnprocessableEntityError => e
|
475
|
+
e
|
476
|
+
end
|
477
|
+
|
478
|
+
expect(error.http_status).to eq(422)
|
479
|
+
expect(error.request_id).to eq('request-id')
|
480
|
+
expect(error.code).to eq('invalid_request_parameters')
|
481
|
+
expect(error.errors).not_to be_nil
|
482
|
+
expect(error.errors).to include('code: missing_required_parameter')
|
483
|
+
expect(error.message).to include('Validation failed')
|
484
|
+
expect(error.message).to include('(code: missing_required_parameter)')
|
485
|
+
end
|
423
486
|
end
|
424
487
|
|
425
488
|
context 'with an expired code' do
|
@@ -440,11 +503,31 @@ describe WorkOS::SSO do
|
|
440
503
|
expect do
|
441
504
|
described_class.profile_and_token(**args)
|
442
505
|
end.to raise_error(
|
443
|
-
WorkOS::
|
444
|
-
"error: invalid_grant, error_description: The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
|
506
|
+
WorkOS::InvalidRequestError,
|
507
|
+
"Status 400, error: invalid_grant, error_description: The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
|
445
508
|
' has expired or is invalid. - request ID: request-id',
|
446
509
|
)
|
447
510
|
end
|
511
|
+
|
512
|
+
it 'raises an exception with proper error object attributes' do
|
513
|
+
expect do
|
514
|
+
described_class.profile_and_token(**args)
|
515
|
+
end.to raise_error(WorkOS::InvalidRequestError)
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'includes proper error attributes' do
|
519
|
+
error = begin
|
520
|
+
described_class.profile_and_token(**args)
|
521
|
+
rescue WorkOS::InvalidRequestError => e
|
522
|
+
e
|
523
|
+
end
|
524
|
+
|
525
|
+
expect(error.http_status).to eq(400)
|
526
|
+
expect(error.request_id).to eq('request-id')
|
527
|
+
expect(error.error).to eq('invalid_grant')
|
528
|
+
expect(error.error_description).to eq("The code '01DVX3C5Z367SFHR8QNDMK7V24' has expired or is invalid.")
|
529
|
+
expect(error.message).to include('invalid_grant')
|
530
|
+
end
|
448
531
|
end
|
449
532
|
end
|
450
533
|
|
@@ -338,6 +338,42 @@ describe WorkOS::UserManagement do
|
|
338
338
|
end
|
339
339
|
end
|
340
340
|
|
341
|
+
it 'only sends non-nil values in request body' do
|
342
|
+
expect(described_class).to receive(:post_request) do |options|
|
343
|
+
body = options[:body]
|
344
|
+
expect(body).to eq({ email: 'test@example.com', first_name: 'John' })
|
345
|
+
expect(body).not_to have_key(:last_name)
|
346
|
+
expect(body).not_to have_key(:email_verified)
|
347
|
+
|
348
|
+
double('request')
|
349
|
+
end.and_return(double('request'))
|
350
|
+
|
351
|
+
expect(described_class).to receive(:execute_request).and_return(
|
352
|
+
double('response', body: '{"id": "test_user", "email": "test@example.com"}'),
|
353
|
+
)
|
354
|
+
|
355
|
+
described_class.create_user(
|
356
|
+
email: 'test@example.com',
|
357
|
+
first_name: 'John',
|
358
|
+
)
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'creates a user with external_id' do
|
362
|
+
VCR.use_cassette 'user_management/create_user_with_external_id' do
|
363
|
+
user = described_class.create_user(
|
364
|
+
email: 'external@example.com',
|
365
|
+
first_name: 'External',
|
366
|
+
last_name: 'User',
|
367
|
+
external_id: 'ext_user_123',
|
368
|
+
)
|
369
|
+
|
370
|
+
expect(user.first_name).to eq('External')
|
371
|
+
expect(user.last_name).to eq('User')
|
372
|
+
expect(user.email).to eq('external@example.com')
|
373
|
+
expect(user.external_id).to eq('ext_user_123')
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
341
377
|
context 'with an invalid payload' do
|
342
378
|
it 'returns an error' do
|
343
379
|
VCR.use_cassette 'user_management/create_user_invalid' do
|
@@ -382,6 +418,49 @@ describe WorkOS::UserManagement do
|
|
382
418
|
end
|
383
419
|
end
|
384
420
|
|
421
|
+
it 'only sends non-nil values in request body' do
|
422
|
+
# Mock the request to inspect what's being sent
|
423
|
+
expect(described_class).to receive(:put_request) do |options|
|
424
|
+
# Verify that the body only contains non-nil values
|
425
|
+
body = options[:body]
|
426
|
+
expect(body).to eq({ email_verified: true })
|
427
|
+
expect(body).not_to have_key(:first_name)
|
428
|
+
expect(body).not_to have_key(:last_name)
|
429
|
+
expect(body).not_to have_key(:email)
|
430
|
+
|
431
|
+
# Return a mock request object
|
432
|
+
double('request')
|
433
|
+
end.and_return(double('request'))
|
434
|
+
|
435
|
+
expect(described_class).to receive(:execute_request).and_return(
|
436
|
+
double('response', body: '{"id": "test_user", "email_verified": true}'),
|
437
|
+
)
|
438
|
+
|
439
|
+
described_class.update_user(
|
440
|
+
id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
|
441
|
+
email_verified: true,
|
442
|
+
)
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'can set external_id to null explicitly' do
|
446
|
+
original_method = described_class.method(:put_request)
|
447
|
+
allow(described_class).to receive(:put_request) do |kwargs|
|
448
|
+
original_method.call(**kwargs)
|
449
|
+
end
|
450
|
+
|
451
|
+
VCR.use_cassette 'user_management/update_user_external_id_null' do
|
452
|
+
described_class.update_user(
|
453
|
+
id: 'user_01K0SR53HJ58M957MYAB6TDZ9X',
|
454
|
+
first_name: 'John',
|
455
|
+
external_id: nil,
|
456
|
+
)
|
457
|
+
end
|
458
|
+
|
459
|
+
expect(described_class).to have_received(:put_request).with(
|
460
|
+
hash_including(body: hash_including(external_id: nil)),
|
461
|
+
)
|
462
|
+
end
|
463
|
+
|
385
464
|
context 'with an invalid payload' do
|
386
465
|
it 'returns an error' do
|
387
466
|
VCR.use_cassette 'user_management/update_user/invalid' do
|
@@ -778,6 +857,28 @@ describe WorkOS::UserManagement do
|
|
778
857
|
expect(authentication_response.authentication_challenge.id).to eq('auth_challenge_01H96FETXGTW1QMBSBT2T36PW0')
|
779
858
|
end
|
780
859
|
end
|
860
|
+
|
861
|
+
it 'only sends non-nil values in request body' do
|
862
|
+
expect(described_class).to receive(:post_request) do |options|
|
863
|
+
body = options[:body]
|
864
|
+
expect(body).to eq({ type: 'totp', totp_issuer: 'Test App' })
|
865
|
+
expect(body).not_to have_key(:totp_user)
|
866
|
+
expect(body).not_to have_key(:totp_secret)
|
867
|
+
|
868
|
+
double('request')
|
869
|
+
end.and_return(double('request'))
|
870
|
+
|
871
|
+
expect(described_class).to receive(:execute_request).and_return(
|
872
|
+
double('response',
|
873
|
+
body: '{"authentication_factor": {"id": "test"}, "authentication_challenge": {"id": "test"}}',),
|
874
|
+
)
|
875
|
+
|
876
|
+
described_class.enroll_auth_factor(
|
877
|
+
user_id: 'user_123',
|
878
|
+
type: 'totp',
|
879
|
+
totp_issuer: 'Test App',
|
880
|
+
)
|
881
|
+
end
|
781
882
|
end
|
782
883
|
|
783
884
|
context 'with an incorrect user id' do
|
@@ -1444,6 +1545,27 @@ describe WorkOS::UserManagement do
|
|
1444
1545
|
expect(invitation.email).to eq('test@workos.com')
|
1445
1546
|
end
|
1446
1547
|
end
|
1548
|
+
|
1549
|
+
it 'only sends non-nil values in request body' do
|
1550
|
+
expect(described_class).to receive(:post_request) do |options|
|
1551
|
+
body = options[:body]
|
1552
|
+
expect(body).to eq({ email: 'test@workos.com', organization_id: 'org_123' })
|
1553
|
+
expect(body).not_to have_key(:expires_in_days)
|
1554
|
+
expect(body).not_to have_key(:inviter_user_id)
|
1555
|
+
expect(body).not_to have_key(:role_slug)
|
1556
|
+
|
1557
|
+
double('request')
|
1558
|
+
end.and_return(double('request'))
|
1559
|
+
|
1560
|
+
expect(described_class).to receive(:execute_request).and_return(
|
1561
|
+
double('response', body: '{"id": "test_invitation"}'),
|
1562
|
+
)
|
1563
|
+
|
1564
|
+
described_class.send_invitation(
|
1565
|
+
email: 'test@workos.com',
|
1566
|
+
organization_id: 'org_123',
|
1567
|
+
)
|
1568
|
+
end
|
1447
1569
|
end
|
1448
1570
|
|
1449
1571
|
context 'with an invalid payload' do
|
@@ -0,0 +1,83 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://api.workos.com/organizations
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"name":"Test Organization with External ID","external_id":"ext_org_123"}'
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
User-Agent:
|
17
|
+
- WorkOS; ruby/3.1.4; arm64-darwin24; v5.20.0
|
18
|
+
Authorization:
|
19
|
+
- Bearer <API_KEY>
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 201
|
23
|
+
message: Created
|
24
|
+
headers:
|
25
|
+
Date:
|
26
|
+
- Tue, 22 Jul 2025 18:55:20 GMT
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
Content-Length:
|
30
|
+
- '286'
|
31
|
+
Connection:
|
32
|
+
- keep-alive
|
33
|
+
Cf-Ray:
|
34
|
+
- 963526d76e29aafd-YYZ
|
35
|
+
Cf-Cache-Status:
|
36
|
+
- DYNAMIC
|
37
|
+
Etag:
|
38
|
+
- W/"11e-Op9TWXVRjSmUm44yQl7F4OmXvVQ"
|
39
|
+
Strict-Transport-Security:
|
40
|
+
- max-age=15552000; includeSubDomains
|
41
|
+
Vary:
|
42
|
+
- Origin, Accept-Encoding
|
43
|
+
Access-Control-Allow-Credentials:
|
44
|
+
- 'true'
|
45
|
+
Content-Security-Policy:
|
46
|
+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
|
47
|
+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
|
48
|
+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
|
49
|
+
Expect-Ct:
|
50
|
+
- max-age=0
|
51
|
+
Referrer-Policy:
|
52
|
+
- no-referrer
|
53
|
+
X-Content-Type-Options:
|
54
|
+
- nosniff
|
55
|
+
X-Dns-Prefetch-Control:
|
56
|
+
- 'off'
|
57
|
+
X-Download-Options:
|
58
|
+
- noopen
|
59
|
+
X-Frame-Options:
|
60
|
+
- SAMEORIGIN
|
61
|
+
X-Permitted-Cross-Domain-Policies:
|
62
|
+
- none
|
63
|
+
X-Request-Id:
|
64
|
+
- 56c9630e-4889-4c81-989b-5a0399cdfcc2
|
65
|
+
X-Xss-Protection:
|
66
|
+
- '0'
|
67
|
+
Report-To:
|
68
|
+
- '{"endpoints":[{"url":"https:\/\/csp-reporting.cloudflare.com\/cdn-cgi\/script_monitor\/report?m=RvRh6EQA2egPx6JdFhsw.m.1RATK00LOdPev9hq3f8A-1753210520-1.0.1.1-Uchst_eeyl0_BAQRRODtUIhYDUBNZKYADoELB62ZrhleV2Q.J_Wdk59lUFdfwSqAAX2vWrW_nejregFofyr3sox0aNmZolb8G_7Nzpy2RD9uyKH4l3OgsDbo.LRttnqfDPXocdCCB9G61E4QJ8Q1ug"}],"group":"cf-csp-endpoint","max_age":86400}'
|
69
|
+
Content-Security-Policy-Report-Only:
|
70
|
+
- script-src 'none'; connect-src 'none'; report-uri https://csp-reporting.cloudflare.com/cdn-cgi/script_monitor/report?m=RvRh6EQA2egPx6JdFhsw.m.1RATK00LOdPev9hq3f8A-1753210520-1.0.1.1-Uchst_eeyl0_BAQRRODtUIhYDUBNZKYADoELB62ZrhleV2Q.J_Wdk59lUFdfwSqAAX2vWrW_nejregFofyr3sox0aNmZolb8G_7Nzpy2RD9uyKH4l3OgsDbo.LRttnqfDPXocdCCB9G61E4QJ8Q1ug;
|
71
|
+
report-to cf-csp-endpoint
|
72
|
+
Set-Cookie:
|
73
|
+
- _cfuvid=PQ8Lx7_xKyiAL1Mx.Ib3Gjf0xXL4n9.aJfbpov473xY-1753210520423-0.0.1.1-604800000;
|
74
|
+
path=/; domain=.workos.com; HttpOnly; Secure; SameSite=None
|
75
|
+
Server:
|
76
|
+
- cloudflare
|
77
|
+
body:
|
78
|
+
encoding: UTF-8
|
79
|
+
string: '{"object":"organization","id":"org_01K0SQV0S6EPWK2ZDEFD1CP1JC","name":"Test
|
80
|
+
Organization with External ID","allow_profiles_outside_organization":false,"created_at":"2025-07-22T18:55:20.355Z","updated_at":"2025-07-22T18:55:20.355Z","domains":[],"metadata":{},"external_id":"ext_org_123"}'
|
81
|
+
http_version:
|
82
|
+
recorded_at: Tue, 22 Jul 2025 18:55:20 GMT
|
83
|
+
recorded_with: VCR 5.0.0
|
@@ -0,0 +1,78 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: put
|
5
|
+
uri: https://api.workos.com/organizations/org_01K0SQV0S6EPWK2ZDEFD1CP1JC
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"name":"Test Organization","external_id":"ext_org_456"}'
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
User-Agent:
|
17
|
+
- WorkOS; ruby/3.1.4; arm64-darwin24; v5.20.0
|
18
|
+
Authorization:
|
19
|
+
- Bearer <API_KEY>
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 200
|
23
|
+
message: OK
|
24
|
+
headers:
|
25
|
+
Date:
|
26
|
+
- Tue, 22 Jul 2025 18:59:20 GMT
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Connection:
|
32
|
+
- keep-alive
|
33
|
+
Cf-Ray:
|
34
|
+
- 96352cb1598936bf-YYZ
|
35
|
+
Cf-Cache-Status:
|
36
|
+
- DYNAMIC
|
37
|
+
Etag:
|
38
|
+
- W/"10d-7PesLGj94PWb6A5HO530ZxGdEf4"
|
39
|
+
Strict-Transport-Security:
|
40
|
+
- max-age=15552000; includeSubDomains
|
41
|
+
Vary:
|
42
|
+
- Origin, Accept-Encoding
|
43
|
+
Access-Control-Allow-Credentials:
|
44
|
+
- 'true'
|
45
|
+
Content-Security-Policy:
|
46
|
+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
|
47
|
+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
|
48
|
+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
|
49
|
+
Expect-Ct:
|
50
|
+
- max-age=0
|
51
|
+
Referrer-Policy:
|
52
|
+
- no-referrer
|
53
|
+
X-Content-Type-Options:
|
54
|
+
- nosniff
|
55
|
+
X-Dns-Prefetch-Control:
|
56
|
+
- 'off'
|
57
|
+
X-Download-Options:
|
58
|
+
- noopen
|
59
|
+
X-Frame-Options:
|
60
|
+
- SAMEORIGIN
|
61
|
+
X-Permitted-Cross-Domain-Policies:
|
62
|
+
- none
|
63
|
+
X-Request-Id:
|
64
|
+
- fdca4330-1a27-4bd5-9e78-75e58eefb233
|
65
|
+
X-Xss-Protection:
|
66
|
+
- '0'
|
67
|
+
Set-Cookie:
|
68
|
+
- _cfuvid=hbA98zPccWnkbrQxoYNYNSHeQq3brYDB.grPijC_WV4-1753210760158-0.0.1.1-604800000;
|
69
|
+
path=/; domain=.workos.com; HttpOnly; Secure; SameSite=None
|
70
|
+
Server:
|
71
|
+
- cloudflare
|
72
|
+
body:
|
73
|
+
encoding: ASCII-8BIT
|
74
|
+
string: '{"object":"organization","id":"org_01K0SQV0S6EPWK2ZDEFD1CP1JC","name":"Test
|
75
|
+
Organization","allow_profiles_outside_organization":false,"created_at":"2025-07-22T18:55:20.355Z","updated_at":"2025-07-22T18:59:20.064Z","domains":[],"metadata":{},"external_id":"ext_org_456"}'
|
76
|
+
http_version:
|
77
|
+
recorded_at: Tue, 22 Jul 2025 18:59:20 GMT
|
78
|
+
recorded_with: VCR 5.0.0
|
@@ -0,0 +1,78 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: put
|
5
|
+
uri: https://api.workos.com/organizations/org_01K0SQV0S6EPWK2ZDEFD1CP1JC
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"name":"Test Organization","external_id":null}'
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
User-Agent:
|
17
|
+
- WorkOS; ruby/3.1.4; arm64-darwin24; v5.22.0
|
18
|
+
Authorization:
|
19
|
+
- Bearer <API_KEY>
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 200
|
23
|
+
message: OK
|
24
|
+
headers:
|
25
|
+
Date:
|
26
|
+
- Wed, 23 Jul 2025 14:19:40 GMT
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Connection:
|
32
|
+
- keep-alive
|
33
|
+
Cf-Ray:
|
34
|
+
- 963bd06b7d9fac70-YYZ
|
35
|
+
Cf-Cache-Status:
|
36
|
+
- DYNAMIC
|
37
|
+
Etag:
|
38
|
+
- W/"104-iVnG8ziU2vR/dhIQFse9HLEGA6c"
|
39
|
+
Strict-Transport-Security:
|
40
|
+
- max-age=15552000; includeSubDomains
|
41
|
+
Vary:
|
42
|
+
- Origin, Accept-Encoding
|
43
|
+
Access-Control-Allow-Credentials:
|
44
|
+
- 'true'
|
45
|
+
Content-Security-Policy:
|
46
|
+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
|
47
|
+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
|
48
|
+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
|
49
|
+
Expect-Ct:
|
50
|
+
- max-age=0
|
51
|
+
Referrer-Policy:
|
52
|
+
- no-referrer
|
53
|
+
X-Content-Type-Options:
|
54
|
+
- nosniff
|
55
|
+
X-Dns-Prefetch-Control:
|
56
|
+
- 'off'
|
57
|
+
X-Download-Options:
|
58
|
+
- noopen
|
59
|
+
X-Frame-Options:
|
60
|
+
- SAMEORIGIN
|
61
|
+
X-Permitted-Cross-Domain-Policies:
|
62
|
+
- none
|
63
|
+
X-Request-Id:
|
64
|
+
- f38969a5-158e-4ed5-b165-a7789d1b0a07
|
65
|
+
X-Xss-Protection:
|
66
|
+
- '0'
|
67
|
+
Set-Cookie:
|
68
|
+
- _cfuvid=7pLWC5qh1CKmolFiECCkKsRg3QAx7aM07F6bX4r6VMU-1753280380885-0.0.1.1-604800000;
|
69
|
+
path=/; domain=.workos.com; HttpOnly; Secure; SameSite=None
|
70
|
+
Server:
|
71
|
+
- cloudflare
|
72
|
+
body:
|
73
|
+
encoding: ASCII-8BIT
|
74
|
+
string: '{"object":"organization","id":"org_01K0SQV0S6EPWK2ZDEFD1CP1JC","name":"Test
|
75
|
+
Organization","allow_profiles_outside_organization":false,"created_at":"2025-07-22T18:55:20.355Z","updated_at":"2025-07-23T14:19:40.831Z","domains":[],"metadata":{},"external_id":null}'
|
76
|
+
http_version:
|
77
|
+
recorded_at: Wed, 23 Jul 2025 14:19:40 GMT
|
78
|
+
recorded_with: VCR 5.0.0
|
@@ -0,0 +1,77 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://api.workos.com/user_management/users
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"email":"external@example.com","password":null,"first_name":"External","last_name":"User","email_verified":null,"external_id":"ext_user_123","password_hash":null,"password_hash_type":null}'
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
User-Agent:
|
17
|
+
- WorkOS; ruby/3.1.4; arm64-darwin24; v5.20.0
|
18
|
+
Authorization:
|
19
|
+
- Bearer <API_KEY>
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 201
|
23
|
+
message: Created
|
24
|
+
headers:
|
25
|
+
Date:
|
26
|
+
- Tue, 22 Jul 2025 19:00:50 GMT
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
Content-Length:
|
30
|
+
- '326'
|
31
|
+
Connection:
|
32
|
+
- keep-alive
|
33
|
+
Cf-Ray:
|
34
|
+
- 96352ee9395c36b3-YYZ
|
35
|
+
Cf-Cache-Status:
|
36
|
+
- DYNAMIC
|
37
|
+
Etag:
|
38
|
+
- W/"146-upR+rp+FopOrmNrHPnshQZCSTFg"
|
39
|
+
Strict-Transport-Security:
|
40
|
+
- max-age=15552000; includeSubDomains
|
41
|
+
Vary:
|
42
|
+
- Origin, Accept-Encoding
|
43
|
+
Access-Control-Allow-Credentials:
|
44
|
+
- 'true'
|
45
|
+
Content-Security-Policy:
|
46
|
+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
|
47
|
+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
|
48
|
+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
|
49
|
+
Expect-Ct:
|
50
|
+
- max-age=0
|
51
|
+
Referrer-Policy:
|
52
|
+
- no-referrer
|
53
|
+
X-Content-Type-Options:
|
54
|
+
- nosniff
|
55
|
+
X-Dns-Prefetch-Control:
|
56
|
+
- 'off'
|
57
|
+
X-Download-Options:
|
58
|
+
- noopen
|
59
|
+
X-Frame-Options:
|
60
|
+
- SAMEORIGIN
|
61
|
+
X-Permitted-Cross-Domain-Policies:
|
62
|
+
- none
|
63
|
+
X-Request-Id:
|
64
|
+
- 0ca01f80-ab79-4dac-ac38-85013ee190fc
|
65
|
+
X-Xss-Protection:
|
66
|
+
- '0'
|
67
|
+
Set-Cookie:
|
68
|
+
- _cfuvid=eS3jraDP_ZTVdNpNKtpQG80hPBRXhXcHuq1V_QbAQjY-1753210850912-0.0.1.1-604800000;
|
69
|
+
path=/; domain=.workos.com; HttpOnly; Secure; SameSite=None
|
70
|
+
Server:
|
71
|
+
- cloudflare
|
72
|
+
body:
|
73
|
+
encoding: UTF-8
|
74
|
+
string: '{"object":"user","id":"user_01K0SR53HJ58M957MYAB6TDZ9X","email":"external@example.com","email_verified":false,"first_name":"External","last_name":"User","profile_picture_url":null,"metadata":{},"last_sign_in_at":null,"created_at":"2025-07-22T19:00:50.852Z","updated_at":"2025-07-22T19:00:50.852Z","external_id":"ext_user_123"}'
|
75
|
+
http_version:
|
76
|
+
recorded_at: Tue, 22 Jul 2025 19:00:50 GMT
|
77
|
+
recorded_with: VCR 5.0.0
|
@@ -0,0 +1,77 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: put
|
5
|
+
uri: https://api.workos.com/user_management/users/user_01K0SR53HJ58M957MYAB6TDZ9X
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"first_name":"John","external_id":null}'
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
User-Agent:
|
17
|
+
- WorkOS; ruby/3.1.4; arm64-darwin24; v5.22.0
|
18
|
+
Authorization:
|
19
|
+
- Bearer <API_KEY>
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 200
|
23
|
+
message: OK
|
24
|
+
headers:
|
25
|
+
Date:
|
26
|
+
- Wed, 23 Jul 2025 14:19:37 GMT
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Connection:
|
32
|
+
- keep-alive
|
33
|
+
Cf-Ray:
|
34
|
+
- 963bd0578b723987-YYZ
|
35
|
+
Cf-Cache-Status:
|
36
|
+
- DYNAMIC
|
37
|
+
Etag:
|
38
|
+
- W/"138-cAQWhb1gyLa/WXSej+rjaxcQD5k"
|
39
|
+
Strict-Transport-Security:
|
40
|
+
- max-age=15552000; includeSubDomains
|
41
|
+
Vary:
|
42
|
+
- Origin, Accept-Encoding
|
43
|
+
Access-Control-Allow-Credentials:
|
44
|
+
- 'true'
|
45
|
+
Content-Security-Policy:
|
46
|
+
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
|
47
|
+
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
|
48
|
+
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
|
49
|
+
Expect-Ct:
|
50
|
+
- max-age=0
|
51
|
+
Referrer-Policy:
|
52
|
+
- no-referrer
|
53
|
+
X-Content-Type-Options:
|
54
|
+
- nosniff
|
55
|
+
X-Dns-Prefetch-Control:
|
56
|
+
- 'off'
|
57
|
+
X-Download-Options:
|
58
|
+
- noopen
|
59
|
+
X-Frame-Options:
|
60
|
+
- SAMEORIGIN
|
61
|
+
X-Permitted-Cross-Domain-Policies:
|
62
|
+
- none
|
63
|
+
X-Request-Id:
|
64
|
+
- e32c5c22-9dba-480d-9b70-cb985f8de386
|
65
|
+
X-Xss-Protection:
|
66
|
+
- '0'
|
67
|
+
Set-Cookie:
|
68
|
+
- _cfuvid=0ljO.TFpHbzOeVWd7XzlanO5UxaeU_RBUAsoWNtWaF0-1753280377738-0.0.1.1-604800000;
|
69
|
+
path=/; domain=.workos.com; HttpOnly; Secure; SameSite=None
|
70
|
+
Server:
|
71
|
+
- cloudflare
|
72
|
+
body:
|
73
|
+
encoding: ASCII-8BIT
|
74
|
+
string: '{"object":"user","id":"user_01K0SR53HJ58M957MYAB6TDZ9X","email":"external@example.com","email_verified":false,"first_name":"John","last_name":"User","profile_picture_url":null,"metadata":{},"last_sign_in_at":null,"created_at":"2025-07-22T19:00:50.852Z","updated_at":"2025-07-23T14:19:37.660Z","external_id":null}'
|
75
|
+
http_version:
|
76
|
+
recorded_at: Wed, 23 Jul 2025 14:19:37 GMT
|
77
|
+
recorded_with: VCR 5.0.0
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: workos
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.23.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WorkOS
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: encryptor
|
@@ -266,6 +266,7 @@ files:
|
|
266
266
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_domains.yml
|
267
267
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_different_payload.yml
|
268
268
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_payload.yml
|
269
|
+
- spec/support/fixtures/vcr_cassettes/organization/create_with_external_id.yml
|
269
270
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_idempotency_key.yml
|
270
271
|
- spec/support/fixtures/vcr_cassettes/organization/create_without_domains.yml
|
271
272
|
- spec/support/fixtures/vcr_cassettes/organization/delete.yml
|
@@ -275,6 +276,8 @@ files:
|
|
275
276
|
- spec/support/fixtures/vcr_cassettes/organization/list.yml
|
276
277
|
- spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml
|
277
278
|
- spec/support/fixtures/vcr_cassettes/organization/update.yml
|
279
|
+
- spec/support/fixtures/vcr_cassettes/organization/update_with_external_id.yml
|
280
|
+
- spec/support/fixtures/vcr_cassettes/organization/update_with_external_id_null.yml
|
278
281
|
- spec/support/fixtures/vcr_cassettes/organization/update_with_stripe_customer_id.yml
|
279
282
|
- spec/support/fixtures/vcr_cassettes/organization/update_without_name.yml
|
280
283
|
- spec/support/fixtures/vcr_cassettes/passwordless/create_session.yml
|
@@ -324,6 +327,7 @@ files:
|
|
324
327
|
- spec/support/fixtures/vcr_cassettes/user_management/create_password_reset/valid.yml
|
325
328
|
- spec/support/fixtures/vcr_cassettes/user_management/create_user_invalid.yml
|
326
329
|
- spec/support/fixtures/vcr_cassettes/user_management/create_user_valid.yml
|
330
|
+
- spec/support/fixtures/vcr_cassettes/user_management/create_user_with_external_id.yml
|
327
331
|
- spec/support/fixtures/vcr_cassettes/user_management/deactivate_organization_membership.yml
|
328
332
|
- spec/support/fixtures/vcr_cassettes/user_management/delete_organization_membership/invalid.yml
|
329
333
|
- spec/support/fixtures/vcr_cassettes/user_management/delete_organization_membership/valid.yml
|
@@ -374,6 +378,7 @@ files:
|
|
374
378
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user/email.yml
|
375
379
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user/invalid.yml
|
376
380
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user/valid.yml
|
381
|
+
- spec/support/fixtures/vcr_cassettes/user_management/update_user_external_id_null.yml
|
377
382
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user_password/invalid.yml
|
378
383
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user_password/valid.yml
|
379
384
|
- spec/support/fixtures/vcr_cassettes/user_management/verify_email/invalid_code.yml
|
@@ -491,6 +496,7 @@ test_files:
|
|
491
496
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_domains.yml
|
492
497
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_different_payload.yml
|
493
498
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_payload.yml
|
499
|
+
- spec/support/fixtures/vcr_cassettes/organization/create_with_external_id.yml
|
494
500
|
- spec/support/fixtures/vcr_cassettes/organization/create_with_idempotency_key.yml
|
495
501
|
- spec/support/fixtures/vcr_cassettes/organization/create_without_domains.yml
|
496
502
|
- spec/support/fixtures/vcr_cassettes/organization/delete.yml
|
@@ -500,6 +506,8 @@ test_files:
|
|
500
506
|
- spec/support/fixtures/vcr_cassettes/organization/list.yml
|
501
507
|
- spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml
|
502
508
|
- spec/support/fixtures/vcr_cassettes/organization/update.yml
|
509
|
+
- spec/support/fixtures/vcr_cassettes/organization/update_with_external_id.yml
|
510
|
+
- spec/support/fixtures/vcr_cassettes/organization/update_with_external_id_null.yml
|
503
511
|
- spec/support/fixtures/vcr_cassettes/organization/update_with_stripe_customer_id.yml
|
504
512
|
- spec/support/fixtures/vcr_cassettes/organization/update_without_name.yml
|
505
513
|
- spec/support/fixtures/vcr_cassettes/passwordless/create_session.yml
|
@@ -549,6 +557,7 @@ test_files:
|
|
549
557
|
- spec/support/fixtures/vcr_cassettes/user_management/create_password_reset/valid.yml
|
550
558
|
- spec/support/fixtures/vcr_cassettes/user_management/create_user_invalid.yml
|
551
559
|
- spec/support/fixtures/vcr_cassettes/user_management/create_user_valid.yml
|
560
|
+
- spec/support/fixtures/vcr_cassettes/user_management/create_user_with_external_id.yml
|
552
561
|
- spec/support/fixtures/vcr_cassettes/user_management/deactivate_organization_membership.yml
|
553
562
|
- spec/support/fixtures/vcr_cassettes/user_management/delete_organization_membership/invalid.yml
|
554
563
|
- spec/support/fixtures/vcr_cassettes/user_management/delete_organization_membership/valid.yml
|
@@ -599,6 +608,7 @@ test_files:
|
|
599
608
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user/email.yml
|
600
609
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user/invalid.yml
|
601
610
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user/valid.yml
|
611
|
+
- spec/support/fixtures/vcr_cassettes/user_management/update_user_external_id_null.yml
|
602
612
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user_password/invalid.yml
|
603
613
|
- spec/support/fixtures/vcr_cassettes/user_management/update_user_password/valid.yml
|
604
614
|
- spec/support/fixtures/vcr_cassettes/user_management/verify_email/invalid_code.yml
|