workos 5.21.0 → 5.22.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/session.rb +1 -0
- data/lib/workos/sso.rb +3 -24
- data/lib/workos/user_management.rb +6 -6
- data/lib/workos/version.rb +1 -1
- 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 +87 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65c18f67663b8681a74442c6771d1527b66fecd20a9c114557255d4ce8d9ca38
|
4
|
+
data.tar.gz: 242b03d06e9caa456b3128d284fee00481fb4e7edec79934fd22c2e57598901b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6f3ccbbc9b6026beee00f92fcb8d87ce3f321ba8be4c808cd524daeb1dc1aa7fa13ef3c9c885096f83e8a68347b70a78d2d9297a396a8071727506e31787c9f
|
7
|
+
data.tar.gz: d8f71832e8767dcfbcc2bcad5760ff5f59cbb3513a73708dc41c50dd5d4f3ac515788a8b81c596b9bb069244d912f3c3a2db9b1e39a0e34ff920bc87a7233b39
|
data/Gemfile.lock
CHANGED
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
|
@@ -206,7 +206,7 @@ module WorkOS
|
|
206
206
|
email_verified: email_verified,
|
207
207
|
password_hash: password_hash,
|
208
208
|
password_hash_type: password_hash_type,
|
209
|
-
},
|
209
|
+
}.compact,
|
210
210
|
auth: true,
|
211
211
|
)
|
212
212
|
|
@@ -251,7 +251,7 @@ module WorkOS
|
|
251
251
|
password: password,
|
252
252
|
password_hash: password_hash,
|
253
253
|
password_hash_type: password_hash_type,
|
254
|
-
},
|
254
|
+
}.compact,
|
255
255
|
auth: true,
|
256
256
|
)
|
257
257
|
|
@@ -643,7 +643,7 @@ module WorkOS
|
|
643
643
|
body: {
|
644
644
|
email: email,
|
645
645
|
invitation_token: invitation_token,
|
646
|
-
},
|
646
|
+
}.compact,
|
647
647
|
auth: true,
|
648
648
|
),
|
649
649
|
)
|
@@ -697,7 +697,7 @@ module WorkOS
|
|
697
697
|
totp_issuer: totp_issuer,
|
698
698
|
totp_user: totp_user,
|
699
699
|
totp_secret: totp_secret,
|
700
|
-
},
|
700
|
+
}.compact,
|
701
701
|
auth: true,
|
702
702
|
),
|
703
703
|
)
|
@@ -928,7 +928,7 @@ module WorkOS
|
|
928
928
|
user_id: user_id,
|
929
929
|
organization_id: organization_id,
|
930
930
|
role_slug: role_slug,
|
931
|
-
},
|
931
|
+
}.compact,
|
932
932
|
auth: true,
|
933
933
|
)
|
934
934
|
|
@@ -1093,7 +1093,7 @@ module WorkOS
|
|
1093
1093
|
expires_in_days: expires_in_days,
|
1094
1094
|
inviter_user_id: inviter_user_id,
|
1095
1095
|
role_slug: role_slug,
|
1096
|
-
},
|
1096
|
+
}.compact,
|
1097
1097
|
auth: true,
|
1098
1098
|
),
|
1099
1099
|
)
|
data/lib/workos/version.rb
CHANGED
@@ -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,26 @@ 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
|
+
|
341
361
|
context 'with an invalid payload' do
|
342
362
|
it 'returns an error' do
|
343
363
|
VCR.use_cassette 'user_management/create_user_invalid' do
|
@@ -382,6 +402,30 @@ describe WorkOS::UserManagement do
|
|
382
402
|
end
|
383
403
|
end
|
384
404
|
|
405
|
+
it 'only sends non-nil values in request body' do
|
406
|
+
# Mock the request to inspect what's being sent
|
407
|
+
expect(described_class).to receive(:put_request) do |options|
|
408
|
+
# Verify that the body only contains non-nil values
|
409
|
+
body = options[:body]
|
410
|
+
expect(body).to eq({ email_verified: true })
|
411
|
+
expect(body).not_to have_key(:first_name)
|
412
|
+
expect(body).not_to have_key(:last_name)
|
413
|
+
expect(body).not_to have_key(:email)
|
414
|
+
|
415
|
+
# Return a mock request object
|
416
|
+
double('request')
|
417
|
+
end.and_return(double('request'))
|
418
|
+
|
419
|
+
expect(described_class).to receive(:execute_request).and_return(
|
420
|
+
double('response', body: '{"id": "test_user", "email_verified": true}'),
|
421
|
+
)
|
422
|
+
|
423
|
+
described_class.update_user(
|
424
|
+
id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
|
425
|
+
email_verified: true,
|
426
|
+
)
|
427
|
+
end
|
428
|
+
|
385
429
|
context 'with an invalid payload' do
|
386
430
|
it 'returns an error' do
|
387
431
|
VCR.use_cassette 'user_management/update_user/invalid' do
|
@@ -778,6 +822,28 @@ describe WorkOS::UserManagement do
|
|
778
822
|
expect(authentication_response.authentication_challenge.id).to eq('auth_challenge_01H96FETXGTW1QMBSBT2T36PW0')
|
779
823
|
end
|
780
824
|
end
|
825
|
+
|
826
|
+
it 'only sends non-nil values in request body' do
|
827
|
+
expect(described_class).to receive(:post_request) do |options|
|
828
|
+
body = options[:body]
|
829
|
+
expect(body).to eq({ type: 'totp', totp_issuer: 'Test App' })
|
830
|
+
expect(body).not_to have_key(:totp_user)
|
831
|
+
expect(body).not_to have_key(:totp_secret)
|
832
|
+
|
833
|
+
double('request')
|
834
|
+
end.and_return(double('request'))
|
835
|
+
|
836
|
+
expect(described_class).to receive(:execute_request).and_return(
|
837
|
+
double('response',
|
838
|
+
body: '{"authentication_factor": {"id": "test"}, "authentication_challenge": {"id": "test"}}',),
|
839
|
+
)
|
840
|
+
|
841
|
+
described_class.enroll_auth_factor(
|
842
|
+
user_id: 'user_123',
|
843
|
+
type: 'totp',
|
844
|
+
totp_issuer: 'Test App',
|
845
|
+
)
|
846
|
+
end
|
781
847
|
end
|
782
848
|
|
783
849
|
context 'with an incorrect user id' do
|
@@ -1444,6 +1510,27 @@ describe WorkOS::UserManagement do
|
|
1444
1510
|
expect(invitation.email).to eq('test@workos.com')
|
1445
1511
|
end
|
1446
1512
|
end
|
1513
|
+
|
1514
|
+
it 'only sends non-nil values in request body' do
|
1515
|
+
expect(described_class).to receive(:post_request) do |options|
|
1516
|
+
body = options[:body]
|
1517
|
+
expect(body).to eq({ email: 'test@workos.com', organization_id: 'org_123' })
|
1518
|
+
expect(body).not_to have_key(:expires_in_days)
|
1519
|
+
expect(body).not_to have_key(:inviter_user_id)
|
1520
|
+
expect(body).not_to have_key(:role_slug)
|
1521
|
+
|
1522
|
+
double('request')
|
1523
|
+
end.and_return(double('request'))
|
1524
|
+
|
1525
|
+
expect(described_class).to receive(:execute_request).and_return(
|
1526
|
+
double('response', body: '{"id": "test_invitation"}'),
|
1527
|
+
)
|
1528
|
+
|
1529
|
+
described_class.send_invitation(
|
1530
|
+
email: 'test@workos.com',
|
1531
|
+
organization_id: 'org_123',
|
1532
|
+
)
|
1533
|
+
end
|
1447
1534
|
end
|
1448
1535
|
|
1449
1536
|
context 'with an invalid payload' do
|
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.22.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-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: encryptor
|