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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44c2f0a70f0a653685d6e7a8ca2601b64c4a1ff43276680ff52d0fcd2c80f5b3
4
- data.tar.gz: 1d3aa7e958196efbe79018014e2ffd5be229dc93812a60725d05a958afcd1c20
3
+ metadata.gz: 840052dd55f646d6ae09f2c0e0a4c91a6686d0f4fcb3b9da66b13fa3e4f835eb
4
+ data.tar.gz: cb5807f1a8b0b1fe28f21e5c8cfa84fd3c75e68bf7e743f9f95a5ac1787efd55
5
5
  SHA512:
6
- metadata.gz: f51ad812297b13109f943a23d15592991b14f2d1c18ba91505c4227fffc64c2ac7912c32df163e974eb95a1f8069b3289f33b1bf783c18e757ba56e7869717d7
7
- data.tar.gz: 5a5428749ac62c22f4fa33db0ad5a491e262c01e445a8318210d09e654e6123a17dec582e9d8b54f09913f123679f1ebe8bc57a2fec7d032f690acf28d77b8a4
6
+ metadata.gz: fccea79a69343e4deeb1f25e076dfc19febbd5a540bd0e9e55ad6f4859ef3332a300e1f023e74c8bad7c16fe1c2b7266eb8bc5dfd600ddb0d40e036ff48d739f
7
+ data.tar.gz: b49a2c19e2360811203f8b07806a198bd7b9307dc654b72fb266311ff7fbf881b0cb142159a67144c25057d340e3d4fdd11bba1fc42e509bf05fcf427dcd9a48
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- workos (5.21.0)
4
+ workos (5.23.0)
5
5
  encryptor (~> 3.0)
6
6
  jwt (~> 2.8)
7
7
 
@@ -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,
@@ -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
  #
@@ -51,6 +51,7 @@ module WorkOS
51
51
  role: decoded['role'],
52
52
  permissions: decoded['permissions'],
53
53
  entitlements: decoded['entitlements'],
54
+ feature_flags: decoded['feature_flags'],
54
55
  user: session[:user],
55
56
  impersonator: session[:impersonator],
56
57
  reason: nil,
data/lib/workos/sso.rb CHANGED
@@ -120,8 +120,9 @@ module WorkOS
120
120
  code: code,
121
121
  }
122
122
 
123
- response = client.request(post_request(path: '/sso/token', body: body))
124
- check_and_raise_profile_and_token_error(response: response)
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: nil,
235
- first_name: nil,
236
- last_name: nil,
237
- email_verified: nil,
238
- external_id: nil,
239
- password: nil,
240
- password_hash: nil,
241
- password_hash_type: nil
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
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WorkOS
4
- VERSION = '5.21.0'
4
+ VERSION = '5.23.0'
5
5
  end
@@ -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,
@@ -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::APIError,
420
- 'error: some error, error_description: some error description - request ID: request-id',
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::APIError,
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.21.0
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-07 00:00:00.000000000 Z
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