workos 5.19.0 → 5.21.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/authentication_response.rb +4 -1
- data/lib/workos/oauth_tokens.rb +29 -0
- data/lib/workos/organizations.rb +8 -1
- data/lib/workos/role.rb +3 -1
- data/lib/workos/user.rb +3 -1
- data/lib/workos/user_management.rb +7 -1
- data/lib/workos/version.rb +1 -1
- data/lib/workos.rb +1 -0
- data/spec/lib/workos/organizations_spec.rb +42 -0
- data/spec/lib/workos/role_spec.rb +142 -0
- data/spec/lib/workos/user_management_spec.rb +62 -0
- data/spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml +7 -7
- data/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid_with_oauth_tokens.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/user_management/update_user/valid.yml +2 -2
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44c2f0a70f0a653685d6e7a8ca2601b64c4a1ff43276680ff52d0fcd2c80f5b3
|
4
|
+
data.tar.gz: 1d3aa7e958196efbe79018014e2ffd5be229dc93812a60725d05a958afcd1c20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f51ad812297b13109f943a23d15592991b14f2d1c18ba91505c4227fffc64c2ac7912c32df163e974eb95a1f8069b3289f33b1bf783c18e757ba56e7869717d7
|
7
|
+
data.tar.gz: 5a5428749ac62c22f4fa33db0ad5a491e262c01e445a8318210d09e654e6123a17dec582e9d8b54f09913f123679f1ebe8bc57a2fec7d032f690acf28d77b8a4
|
data/Gemfile.lock
CHANGED
@@ -12,7 +12,8 @@ module WorkOS
|
|
12
12
|
:access_token,
|
13
13
|
:refresh_token,
|
14
14
|
:authentication_method,
|
15
|
-
:sealed_session
|
15
|
+
:sealed_session,
|
16
|
+
:oauth_tokens
|
16
17
|
|
17
18
|
# rubocop:disable Metrics/AbcSize
|
18
19
|
def initialize(authentication_response_json, session = nil)
|
@@ -27,6 +28,7 @@ module WorkOS
|
|
27
28
|
reason: impersonator_json[:reason],)
|
28
29
|
end
|
29
30
|
@authentication_method = json[:authentication_method]
|
31
|
+
@oauth_tokens = json[:oauth_tokens] ? WorkOS::OAuthTokens.new(json[:oauth_tokens].to_json) : nil
|
30
32
|
@sealed_session =
|
31
33
|
if session && session[:seal_session]
|
32
34
|
WorkOS::Session.seal_data({
|
@@ -49,6 +51,7 @@ module WorkOS
|
|
49
51
|
refresh_token: refresh_token,
|
50
52
|
authentication_method: authentication_method,
|
51
53
|
sealed_session: sealed_session,
|
54
|
+
oauth_tokens: oauth_tokens&.to_json,
|
52
55
|
}
|
53
56
|
end
|
54
57
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WorkOS
|
4
|
+
# The OAuthTokens class represents the third party provider OAuth tokens returned in the authentication response.
|
5
|
+
# This class is not meant to be instantiated in user space, and is instantiated internally but exposed.
|
6
|
+
class OAuthTokens
|
7
|
+
include HashProvider
|
8
|
+
|
9
|
+
attr_accessor :access_token, :refresh_token, :scopes, :expires_at
|
10
|
+
|
11
|
+
def initialize(json)
|
12
|
+
hash = JSON.parse(json, symbolize_names: true)
|
13
|
+
|
14
|
+
@access_token = hash[:access_token]
|
15
|
+
@refresh_token = hash[:refresh_token]
|
16
|
+
@scopes = hash[:scopes]
|
17
|
+
@expires_at = hash[:expires_at]
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_json(*)
|
21
|
+
{
|
22
|
+
access_token: access_token,
|
23
|
+
refresh_token: refresh_token,
|
24
|
+
scopes: scopes,
|
25
|
+
expires_at: expires_at,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/workos/organizations.rb
CHANGED
@@ -185,7 +185,14 @@ module WorkOS
|
|
185
185
|
|
186
186
|
# Retrieve a list of roles for the given organization.
|
187
187
|
#
|
188
|
-
# @param [String]
|
188
|
+
# @param [String] organization_id The ID of the organization to fetch roles for.
|
189
|
+
#
|
190
|
+
# @example
|
191
|
+
# WorkOS::Organizations.list_organization_roles(organization_id: 'org_01EHZNVPK3SFK441A1RGBFSHRT')
|
192
|
+
# => #<WorkOS::Types::ListStruct data=[#<WorkOS::Role id="role_123" name="Admin" slug="admin"
|
193
|
+
# permissions=["admin:all"] ...>] ...>
|
194
|
+
#
|
195
|
+
# @return [WorkOS::Types::ListStruct] - Collection of Role objects, each including permissions array
|
189
196
|
def list_organization_roles(organization_id:)
|
190
197
|
response = execute_request(
|
191
198
|
request: get_request(
|
data/lib/workos/role.rb
CHANGED
@@ -7,7 +7,7 @@ module WorkOS
|
|
7
7
|
class Role
|
8
8
|
include HashProvider
|
9
9
|
|
10
|
-
attr_accessor :id, :name, :slug, :description, :type, :created_at, :updated_at
|
10
|
+
attr_accessor :id, :name, :slug, :description, :permissions, :type, :created_at, :updated_at
|
11
11
|
|
12
12
|
def initialize(json)
|
13
13
|
hash = JSON.parse(json, symbolize_names: true)
|
@@ -16,6 +16,7 @@ module WorkOS
|
|
16
16
|
@name = hash[:name]
|
17
17
|
@slug = hash[:slug]
|
18
18
|
@description = hash[:description]
|
19
|
+
@permissions = hash[:permissions] || []
|
19
20
|
@type = hash[:type]
|
20
21
|
@created_at = hash[:created_at]
|
21
22
|
@updated_at = hash[:updated_at]
|
@@ -27,6 +28,7 @@ module WorkOS
|
|
27
28
|
name: name,
|
28
29
|
slug: slug,
|
29
30
|
description: description,
|
31
|
+
permissions: permissions,
|
30
32
|
type: type,
|
31
33
|
created_at: created_at,
|
32
34
|
updated_at: updated_at,
|
data/lib/workos/user.rb
CHANGED
@@ -8,7 +8,7 @@ module WorkOS
|
|
8
8
|
include HashProvider
|
9
9
|
|
10
10
|
attr_accessor :id, :email, :first_name, :last_name, :email_verified,
|
11
|
-
:profile_picture_url, :last_sign_in_at, :created_at, :updated_at
|
11
|
+
:profile_picture_url, :external_id, :last_sign_in_at, :created_at, :updated_at
|
12
12
|
|
13
13
|
def initialize(json)
|
14
14
|
hash = JSON.parse(json, symbolize_names: true)
|
@@ -19,6 +19,7 @@ module WorkOS
|
|
19
19
|
@last_name = hash[:last_name]
|
20
20
|
@email_verified = hash[:email_verified]
|
21
21
|
@profile_picture_url = hash[:profile_picture_url]
|
22
|
+
@external_id = hash[:external_id]
|
22
23
|
@last_sign_in_at = hash[:last_sign_in_at]
|
23
24
|
@created_at = hash[:created_at]
|
24
25
|
@updated_at = hash[:updated_at]
|
@@ -32,6 +33,7 @@ module WorkOS
|
|
32
33
|
last_name: last_name,
|
33
34
|
email_verified: email_verified,
|
34
35
|
profile_picture_url: profile_picture_url,
|
36
|
+
external_id: external_id,
|
35
37
|
last_sign_in_at: last_sign_in_at,
|
36
38
|
created_at: created_at,
|
37
39
|
updated_at: updated_at,
|
@@ -71,6 +71,7 @@ module WorkOS
|
|
71
71
|
# field of the IdP sign-in page for the user, if you know their username ahead of time.
|
72
72
|
# @param [String] domain_hint Can be used to pre-fill the domain field when
|
73
73
|
# initiating authentication with Microsoft OAuth, or with a GoogleSAML connection type.
|
74
|
+
# @param [Array<String>] provider_scopes An array of additional OAuth scopes to request from the provider.
|
74
75
|
# @example
|
75
76
|
# WorkOS::UserManagement.authorization_url(
|
76
77
|
# connection_id: 'conn_123',
|
@@ -96,7 +97,8 @@ module WorkOS
|
|
96
97
|
provider: nil,
|
97
98
|
connection_id: nil,
|
98
99
|
organization_id: nil,
|
99
|
-
state: ''
|
100
|
+
state: '',
|
101
|
+
provider_scopes: nil
|
100
102
|
)
|
101
103
|
|
102
104
|
validate_authorization_url_arguments(
|
@@ -115,6 +117,7 @@ module WorkOS
|
|
115
117
|
provider: provider,
|
116
118
|
connection_id: connection_id,
|
117
119
|
organization_id: organization_id,
|
120
|
+
provider_scopes: provider_scopes,
|
118
121
|
}.compact)
|
119
122
|
|
120
123
|
"https://#{WorkOS.config.api_hostname}/user_management/authorize?#{query}"
|
@@ -219,6 +222,7 @@ module WorkOS
|
|
219
222
|
# @param [String] first_name The user's first name.
|
220
223
|
# @param [String] last_name The user's last name.
|
221
224
|
# @param [Boolean] email_verified Whether the user's email address was previously verified.
|
225
|
+
# @param [String] external_id The users's external ID
|
222
226
|
# @param [String] password The user's password.
|
223
227
|
# @param [String] password_hash The user's hashed password.
|
224
228
|
# @option [String] password_hash_type The algorithm originally used to hash the password.
|
@@ -231,6 +235,7 @@ module WorkOS
|
|
231
235
|
first_name: nil,
|
232
236
|
last_name: nil,
|
233
237
|
email_verified: nil,
|
238
|
+
external_id: nil,
|
234
239
|
password: nil,
|
235
240
|
password_hash: nil,
|
236
241
|
password_hash_type: nil
|
@@ -242,6 +247,7 @@ module WorkOS
|
|
242
247
|
first_name: first_name,
|
243
248
|
last_name: last_name,
|
244
249
|
email_verified: email_verified,
|
250
|
+
external_id: external_id,
|
245
251
|
password: password,
|
246
252
|
password_hash: password_hash,
|
247
253
|
password_hash_type: password_hash_type,
|
data/lib/workos/version.rb
CHANGED
data/lib/workos.rb
CHANGED
@@ -63,6 +63,7 @@ module WorkOS
|
|
63
63
|
autoload :Invitation, 'workos/invitation'
|
64
64
|
autoload :MagicAuth, 'workos/magic_auth'
|
65
65
|
autoload :MFA, 'workos/mfa'
|
66
|
+
autoload :OAuthTokens, 'workos/oauth_tokens'
|
66
67
|
autoload :Organization, 'workos/organization'
|
67
68
|
autoload :Organizations, 'workos/organizations'
|
68
69
|
autoload :OrganizationMembership, 'workos/organization_membership'
|
@@ -354,6 +354,48 @@ describe WorkOS::Organizations do
|
|
354
354
|
expect(roles.list_metadata).to eq(expected_metadata)
|
355
355
|
end
|
356
356
|
end
|
357
|
+
|
358
|
+
it 'returns properly initialized Role objects with all attributes' do
|
359
|
+
VCR.use_cassette 'organization/list_organization_roles' do
|
360
|
+
roles = described_class.list_organization_roles(organization_id: 'org_01JEXP6Z3X7HE4CB6WQSH9ZAFE')
|
361
|
+
|
362
|
+
first_role = roles.data.first
|
363
|
+
expect(first_role).to be_a(WorkOS::Role)
|
364
|
+
expect(first_role.id).to eq('role_01HS1C7GRJE08PBR3M6Y0ZYGDZ')
|
365
|
+
expect(first_role.name).to eq('Admin')
|
366
|
+
expect(first_role.slug).to eq('admin')
|
367
|
+
expect(first_role.description).to eq('Write access to every resource available')
|
368
|
+
expect(first_role.permissions).to eq(['admin:all', 'read:users', 'write:users', 'manage:roles'])
|
369
|
+
expect(first_role.type).to eq('EnvironmentRole')
|
370
|
+
expect(first_role.created_at).to eq('2024-03-15T15:38:29.521Z')
|
371
|
+
expect(first_role.updated_at).to eq('2024-11-14T17:08:00.556Z')
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
it 'handles roles with empty permissions arrays' do
|
376
|
+
VCR.use_cassette 'organization/list_organization_roles' do
|
377
|
+
roles = described_class.list_organization_roles(organization_id: 'org_01JEXP6Z3X7HE4CB6WQSH9ZAFE')
|
378
|
+
|
379
|
+
platform_manager_role = roles.data.find { |role| role.slug == 'org-platform-manager' }
|
380
|
+
expect(platform_manager_role).to be_a(WorkOS::Role)
|
381
|
+
expect(platform_manager_role.permissions).to eq([])
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'properly serializes Role objects including permissions' do
|
386
|
+
VCR.use_cassette 'organization/list_organization_roles' do
|
387
|
+
roles = described_class.list_organization_roles(organization_id: 'org_01JEXP6Z3X7HE4CB6WQSH9ZAFE')
|
388
|
+
|
389
|
+
billing_role = roles.data.find { |role| role.slug == 'billing' }
|
390
|
+
serialized = billing_role.to_json
|
391
|
+
|
392
|
+
expect(serialized[:id]).to eq('role_01JA8GJZRDSZEB9289DQXJ3N9Z')
|
393
|
+
expect(serialized[:name]).to eq('Billing Manager')
|
394
|
+
expect(serialized[:slug]).to eq('billing')
|
395
|
+
expect(serialized[:permissions]).to eq(['read:billing', 'write:billing'])
|
396
|
+
expect(serialized[:type]).to eq('EnvironmentRole')
|
397
|
+
end
|
398
|
+
end
|
357
399
|
end
|
358
400
|
end
|
359
401
|
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe WorkOS::Role do
|
4
|
+
describe '.initialize' do
|
5
|
+
context 'with full role data including permissions' do
|
6
|
+
it 'initializes all attributes correctly' do
|
7
|
+
role_json = {
|
8
|
+
id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY',
|
9
|
+
name: 'Admin',
|
10
|
+
slug: 'admin',
|
11
|
+
description: 'Administrator role with full access',
|
12
|
+
permissions: ['read:users', 'write:users', 'admin:all'],
|
13
|
+
type: 'system',
|
14
|
+
created_at: '2022-05-13T17:45:31.732Z',
|
15
|
+
updated_at: '2022-07-13T17:45:42.618Z',
|
16
|
+
}.to_json
|
17
|
+
|
18
|
+
role = described_class.new(role_json)
|
19
|
+
|
20
|
+
expect(role.id).to eq('role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY')
|
21
|
+
expect(role.name).to eq('Admin')
|
22
|
+
expect(role.slug).to eq('admin')
|
23
|
+
expect(role.description).to eq('Administrator role with full access')
|
24
|
+
expect(role.permissions).to eq(['read:users', 'write:users', 'admin:all'])
|
25
|
+
expect(role.type).to eq('system')
|
26
|
+
expect(role.created_at).to eq('2022-05-13T17:45:31.732Z')
|
27
|
+
expect(role.updated_at).to eq('2022-07-13T17:45:42.618Z')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with role data without permissions' do
|
32
|
+
it 'initializes permissions as empty array' do
|
33
|
+
role_json = {
|
34
|
+
id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY',
|
35
|
+
name: 'User',
|
36
|
+
slug: 'user',
|
37
|
+
description: 'Basic user role',
|
38
|
+
type: 'custom',
|
39
|
+
created_at: '2022-05-13T17:45:31.732Z',
|
40
|
+
updated_at: '2022-07-13T17:45:42.618Z',
|
41
|
+
}.to_json
|
42
|
+
|
43
|
+
role = described_class.new(role_json)
|
44
|
+
|
45
|
+
expect(role.id).to eq('role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY')
|
46
|
+
expect(role.name).to eq('User')
|
47
|
+
expect(role.slug).to eq('user')
|
48
|
+
expect(role.description).to eq('Basic user role')
|
49
|
+
expect(role.permissions).to eq([])
|
50
|
+
expect(role.type).to eq('custom')
|
51
|
+
expect(role.created_at).to eq('2022-05-13T17:45:31.732Z')
|
52
|
+
expect(role.updated_at).to eq('2022-07-13T17:45:42.618Z')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with role data with null permissions' do
|
57
|
+
it 'initializes permissions as empty array' do
|
58
|
+
role_json = {
|
59
|
+
id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY',
|
60
|
+
name: 'User',
|
61
|
+
slug: 'user',
|
62
|
+
description: 'Basic user role',
|
63
|
+
permissions: nil,
|
64
|
+
type: 'custom',
|
65
|
+
created_at: '2022-05-13T17:45:31.732Z',
|
66
|
+
updated_at: '2022-07-13T17:45:42.618Z',
|
67
|
+
}.to_json
|
68
|
+
|
69
|
+
role = described_class.new(role_json)
|
70
|
+
|
71
|
+
expect(role.permissions).to eq([])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'with role data with empty permissions array' do
|
76
|
+
it 'preserves empty permissions array' do
|
77
|
+
role_json = {
|
78
|
+
id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY',
|
79
|
+
name: 'User',
|
80
|
+
slug: 'user',
|
81
|
+
description: 'Basic user role',
|
82
|
+
permissions: [],
|
83
|
+
type: 'custom',
|
84
|
+
created_at: '2022-05-13T17:45:31.732Z',
|
85
|
+
updated_at: '2022-07-13T17:45:42.618Z',
|
86
|
+
}.to_json
|
87
|
+
|
88
|
+
role = described_class.new(role_json)
|
89
|
+
|
90
|
+
expect(role.permissions).to eq([])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '.to_json' do
|
96
|
+
context 'with role that has permissions' do
|
97
|
+
it 'includes permissions in serialized output' do
|
98
|
+
role_json = {
|
99
|
+
id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY',
|
100
|
+
name: 'Admin',
|
101
|
+
slug: 'admin',
|
102
|
+
description: 'Administrator role',
|
103
|
+
permissions: ['read:all', 'write:all'],
|
104
|
+
type: 'system',
|
105
|
+
created_at: '2022-05-13T17:45:31.732Z',
|
106
|
+
updated_at: '2022-07-13T17:45:42.618Z',
|
107
|
+
}.to_json
|
108
|
+
|
109
|
+
role = described_class.new(role_json)
|
110
|
+
serialized = role.to_json
|
111
|
+
|
112
|
+
expect(serialized[:id]).to eq('role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY')
|
113
|
+
expect(serialized[:name]).to eq('Admin')
|
114
|
+
expect(serialized[:slug]).to eq('admin')
|
115
|
+
expect(serialized[:description]).to eq('Administrator role')
|
116
|
+
expect(serialized[:permissions]).to eq(['read:all', 'write:all'])
|
117
|
+
expect(serialized[:type]).to eq('system')
|
118
|
+
expect(serialized[:created_at]).to eq('2022-05-13T17:45:31.732Z')
|
119
|
+
expect(serialized[:updated_at]).to eq('2022-07-13T17:45:42.618Z')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'with role that has no permissions' do
|
124
|
+
it 'includes empty permissions array in serialized output' do
|
125
|
+
role_json = {
|
126
|
+
id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY',
|
127
|
+
name: 'User',
|
128
|
+
slug: 'user',
|
129
|
+
description: 'Basic user role',
|
130
|
+
type: 'custom',
|
131
|
+
created_at: '2022-05-13T17:45:31.732Z',
|
132
|
+
updated_at: '2022-07-13T17:45:42.618Z',
|
133
|
+
}.to_json
|
134
|
+
|
135
|
+
role = described_class.new(role_json)
|
136
|
+
serialized = role.to_json
|
137
|
+
|
138
|
+
expect(serialized[:permissions]).to eq([])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -36,6 +36,32 @@ describe WorkOS::UserManagement do
|
|
36
36
|
'edit%22%7D&provider=authkit',
|
37
37
|
)
|
38
38
|
end
|
39
|
+
|
40
|
+
context 'with provider_scopes' do
|
41
|
+
it 'returns a valid authorization URL that includes provider_scopes' do
|
42
|
+
url = WorkOS::UserManagement.authorization_url(
|
43
|
+
provider: 'GoogleOAuth',
|
44
|
+
provider_scopes: %w[custom-scope-1 custom-scope-2],
|
45
|
+
client_id: 'workos-proj-123',
|
46
|
+
redirect_uri: 'foo.com/auth/callback',
|
47
|
+
state: {
|
48
|
+
next_page: '/dashboard/edit',
|
49
|
+
}.to_s,
|
50
|
+
)
|
51
|
+
|
52
|
+
expect(url).to eq(
|
53
|
+
'https://api.workos.com/user_management/authorize?' \
|
54
|
+
'client_id=workos-proj-123' \
|
55
|
+
'&redirect_uri=foo.com%2Fauth%2Fcallback' \
|
56
|
+
'&response_type=code' \
|
57
|
+
'&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
|
58
|
+
'edit%22%7D' \
|
59
|
+
'&provider=GoogleOAuth' \
|
60
|
+
'&provider_scopes=custom-scope-1' \
|
61
|
+
'&provider_scopes=custom-scope-2',
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
39
65
|
end
|
40
66
|
|
41
67
|
context 'with a connection selector' do
|
@@ -336,10 +362,12 @@ describe WorkOS::UserManagement do
|
|
336
362
|
first_name: 'Jane',
|
337
363
|
last_name: 'Doe',
|
338
364
|
email_verified: false,
|
365
|
+
external_id: '123',
|
339
366
|
)
|
340
367
|
expect(user.first_name).to eq('Jane')
|
341
368
|
expect(user.last_name).to eq('Doe')
|
342
369
|
expect(user.email_verified).to eq(false)
|
370
|
+
expect(user.external_id).to eq('123')
|
343
371
|
end
|
344
372
|
end
|
345
373
|
|
@@ -453,6 +481,40 @@ describe WorkOS::UserManagement do
|
|
453
481
|
end
|
454
482
|
end
|
455
483
|
|
484
|
+
context 'when oauth_tokens is present in the api response' do
|
485
|
+
it 'returns an oauth_tokens object' do
|
486
|
+
VCR.use_cassette('user_management/authenticate_with_code/valid_with_oauth_tokens') do
|
487
|
+
authentication_response = WorkOS::UserManagement.authenticate_with_code(
|
488
|
+
code: '01H93ZZHA0JBHFJH9RR11S83YN',
|
489
|
+
client_id: 'client_123',
|
490
|
+
ip_address: '200.240.210.16',
|
491
|
+
user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
|
492
|
+
)
|
493
|
+
|
494
|
+
expect(authentication_response.oauth_tokens).to be_a(WorkOS::OAuthTokens)
|
495
|
+
expect(authentication_response.oauth_tokens.access_token).to eq('oauth_access_token')
|
496
|
+
expect(authentication_response.oauth_tokens.refresh_token).to eq('oauth_refresh_token')
|
497
|
+
expect(authentication_response.oauth_tokens.scopes).to eq(%w[read write])
|
498
|
+
expect(authentication_response.oauth_tokens.expires_at).to eq(1_234_567_890)
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
context 'when oauth_tokens is not present in the api response' do
|
504
|
+
it 'returns nil oauth_tokens' do
|
505
|
+
VCR.use_cassette('user_management/authenticate_with_code/valid') do
|
506
|
+
authentication_response = WorkOS::UserManagement.authenticate_with_code(
|
507
|
+
code: '01H93ZZHA0JBHFJH9RR11S83YN',
|
508
|
+
client_id: 'client_123',
|
509
|
+
ip_address: '200.240.210.16',
|
510
|
+
user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36',
|
511
|
+
)
|
512
|
+
|
513
|
+
expect(authentication_response.oauth_tokens).to be_nil
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
456
518
|
context 'when the user is being impersonated' do
|
457
519
|
it 'contains the impersonator metadata' do
|
458
520
|
VCR.use_cassette('user_management/authenticate_with_code/valid_with_impersonator') do
|
@@ -70,13 +70,13 @@ http_interactions:
|
|
70
70
|
encoding: ASCII-8BIT
|
71
71
|
string:
|
72
72
|
'{"object":"list","data":[{"object":"role","id":"role_01HS1C7GRJE08PBR3M6Y0ZYGDZ","description":"Write
|
73
|
-
access to every resource available","name":"Admin","slug":"admin","type":"EnvironmentRole","created_at":"2024-03-15T15:38:29.521Z","updated_at":"2024-11-14T17:08:00.556Z"},{"object":"role","id":"role_01JA8GJZRDSZEB9289DQXJ3N9Z","description":"","name":"Billing
|
74
|
-
Manager","slug":"billing","type":"EnvironmentRole","created_at":"2024-10-15T16:36:11.653Z","updated_at":"2024-12-19T21:27:01.286Z"},{"object":"role","id":"role_01HSBH4R6RX0V86S3R590NNZW2","description":"Developer
|
75
|
-
role","name":"Developer","slug":"developer","type":"EnvironmentRole","created_at":"2024-03-19T14:16:46.038Z","updated_at":"2024-03-19T14:16:46.038Z"},{"object":"role","id":"role_01HS4GDWJ8T6NQPTX2D0R5KBHN","description":"Edit
|
76
|
-
and view access to non-critical resources","name":"Editor","slug":"editor","type":"EnvironmentRole","created_at":"2024-03-16T20:49:35.815Z","updated_at":"2024-03-16T20:52:19.410Z"},{"object":"role","id":"role_01HRFZE22WS2MGX6EWAG2JX6NW","description":"The
|
77
|
-
default user role","name":"Member","slug":"member","type":"EnvironmentRole","created_at":"2024-03-08T21:27:47.034Z","updated_at":"2024-08-14T00:27:46.265Z"},{"object":"role","id":"role_01JEYJ2Z5MYG0TZYTDF02MW11N","description":"Manage
|
78
|
-
billing for organization.","name":"Billing manager","slug":"org-billing-manager","type":"OrganizationRole","created_at":"2024-12-12T23:08:28.712Z","updated_at":"2024-12-12T23:08:28.712Z"},{"object":"role","id":"role_01JF0B7MQ9X414WQRAQMQYE1GS","description":"","name":"Platform
|
79
|
-
Manager","slug":"org-platform-manager","type":"OrganizationRole","created_at":"2024-12-13T15:47:10.692Z","updated_at":"2024-12-13T15:47:10.692Z"}]}'
|
73
|
+
access to every resource available","name":"Admin","slug":"admin","permissions":["admin:all","read:users","write:users","manage:roles"],"type":"EnvironmentRole","created_at":"2024-03-15T15:38:29.521Z","updated_at":"2024-11-14T17:08:00.556Z"},{"object":"role","id":"role_01JA8GJZRDSZEB9289DQXJ3N9Z","description":"","name":"Billing
|
74
|
+
Manager","slug":"billing","permissions":["read:billing","write:billing"],"type":"EnvironmentRole","created_at":"2024-10-15T16:36:11.653Z","updated_at":"2024-12-19T21:27:01.286Z"},{"object":"role","id":"role_01HSBH4R6RX0V86S3R590NNZW2","description":"Developer
|
75
|
+
role","name":"Developer","slug":"developer","permissions":["read:code","write:code","deploy:apps"],"type":"EnvironmentRole","created_at":"2024-03-19T14:16:46.038Z","updated_at":"2024-03-19T14:16:46.038Z"},{"object":"role","id":"role_01HS4GDWJ8T6NQPTX2D0R5KBHN","description":"Edit
|
76
|
+
and view access to non-critical resources","name":"Editor","slug":"editor","permissions":["read:content","write:content","publish:content"],"type":"EnvironmentRole","created_at":"2024-03-16T20:49:35.815Z","updated_at":"2024-03-16T20:52:19.410Z"},{"object":"role","id":"role_01HRFZE22WS2MGX6EWAG2JX6NW","description":"The
|
77
|
+
default user role","name":"Member","slug":"member","permissions":["read:basic"],"type":"EnvironmentRole","created_at":"2024-03-08T21:27:47.034Z","updated_at":"2024-08-14T00:27:46.265Z"},{"object":"role","id":"role_01JEYJ2Z5MYG0TZYTDF02MW11N","description":"Manage
|
78
|
+
billing for organization.","name":"Billing manager","slug":"org-billing-manager","permissions":["read:org:billing","write:org:billing"],"type":"OrganizationRole","created_at":"2024-12-12T23:08:28.712Z","updated_at":"2024-12-12T23:08:28.712Z"},{"object":"role","id":"role_01JF0B7MQ9X414WQRAQMQYE1GS","description":"","name":"Platform
|
79
|
+
Manager","slug":"org-platform-manager","permissions":[],"type":"OrganizationRole","created_at":"2024-12-13T15:47:10.692Z","updated_at":"2024-12-13T15:47:10.692Z"}]}'
|
80
80
|
http_version:
|
81
81
|
recorded_at: Mon, 23 Dec 2024 20:23:07 GMT
|
82
82
|
recorded_with: VCR 5.0.0
|
@@ -0,0 +1,82 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://api.workos.com/user_management/authenticate
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string:
|
9
|
+
'{"code":"01H93ZZHA0JBHFJH9RR11S83YN","client_id":"client_123","client_secret":"<API_KEY>","ip_address":"200.240.210.16","user_agent":"Mozilla/5.0
|
10
|
+
(Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36","grant_type":"authorization_code"}'
|
11
|
+
headers:
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Accept-Encoding:
|
15
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
16
|
+
Accept:
|
17
|
+
- "*/*"
|
18
|
+
User-Agent:
|
19
|
+
- WorkOS; ruby/3.0.2; arm64-darwin21; v2.16.0
|
20
|
+
response:
|
21
|
+
status:
|
22
|
+
code: 200
|
23
|
+
message: OK
|
24
|
+
headers:
|
25
|
+
Date:
|
26
|
+
- Wed, 30 Aug 2023 19:51:51 GMT
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=utf-8
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Connection:
|
32
|
+
- keep-alive
|
33
|
+
Cf-Ray:
|
34
|
+
- 7fef921deeca091f-SEA
|
35
|
+
Cf-Cache-Status:
|
36
|
+
- DYNAMIC
|
37
|
+
Etag:
|
38
|
+
- W/"13b-pHataL1lHEvsW5EO4vq5QgAdcWw"
|
39
|
+
Strict-Transport-Security:
|
40
|
+
- max-age=15552000; includeSubDomains
|
41
|
+
Vary:
|
42
|
+
- Origin, Accept-Encoding
|
43
|
+
Via:
|
44
|
+
- 1.1 spaces-router (devel)
|
45
|
+
Access-Control-Allow-Credentials:
|
46
|
+
- "true"
|
47
|
+
Content-Security-Policy:
|
48
|
+
- "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self'
|
49
|
+
https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src
|
50
|
+
'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests"
|
51
|
+
Expect-Ct:
|
52
|
+
- max-age=0
|
53
|
+
Referrer-Policy:
|
54
|
+
- no-referrer
|
55
|
+
X-Content-Type-Options:
|
56
|
+
- nosniff
|
57
|
+
X-Dns-Prefetch-Control:
|
58
|
+
- "off"
|
59
|
+
X-Download-Options:
|
60
|
+
- noopen
|
61
|
+
X-Frame-Options:
|
62
|
+
- SAMEORIGIN
|
63
|
+
X-Permitted-Cross-Domain-Policies:
|
64
|
+
- none
|
65
|
+
X-Request-Id:
|
66
|
+
- 630bec5a-5a13-4311-a0b7-958889a3bbb2
|
67
|
+
X-Xss-Protection:
|
68
|
+
- "0"
|
69
|
+
Set-Cookie:
|
70
|
+
- __cf_bm=o5KBdIAUFZp0azSQnnd1GlQcIlcPCz95uFg6hFNnKM8-1693425111-0-ARSauqdojZdKD6Z7vp12JBrxCp6wE1s0JzEhaN0XE2DqME76OnJiDJugj2TsbNGXtqWaH3By7XHUXVZDf+AdFxU=;
|
71
|
+
path=/; expires=Wed, 30-Aug-23 20:21:51 GMT; domain=.workos.com; HttpOnly;
|
72
|
+
Secure; SameSite=None
|
73
|
+
- __cfruid=3e9a5d359ba92753e7626245fef8b2f1ee096477-1693425111; path=/; domain=.workos.com;
|
74
|
+
HttpOnly; Secure; SameSite=None
|
75
|
+
Server:
|
76
|
+
- cloudflare
|
77
|
+
body:
|
78
|
+
encoding: ASCII-8BIT
|
79
|
+
string: '{"user":{"object":"user","id":"user_01H93ZY4F80YZRRS6N59Z2HFVS","email":"test@workos.app","email_verified":false,"first_name":"Lucille","last_name":"Bluth","created_at":"2023-08-30T19:50:13.214Z","updated_at":"2023-08-30T19:50:13.214Z","user_type":"managed","sso_profile_id":"prof_01H93ZTVWYPAT4RKDSPFPPXH0J"},"access_token":"<ACCESS_TOKEN>","refresh_token":"<REFRESH_TOKEN>","oauth_tokens":{"access_token":"oauth_access_token","refresh_token":"oauth_refresh_token","scopes":["read","write"],"expires_at":1234567890}}'
|
80
|
+
http_version:
|
81
|
+
recorded_at: Wed, 30 Aug 2023 19:51:51 GMT
|
82
|
+
recorded_with: VCR 5.0.0
|
@@ -5,7 +5,7 @@ http_interactions:
|
|
5
5
|
uri: https://api.workos.com/user_management/users/user_01H7TVSKS45SDHN5V9XPSM6H44
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
|
-
string: '{"first_name":"Jane","last_name":"Doe","email_verified":false}'
|
8
|
+
string: '{"first_name":"Jane","last_name":"Doe","email_verified":false,"external_id":"123"}'
|
9
9
|
headers:
|
10
10
|
Content-Type:
|
11
11
|
- application/json
|
@@ -76,7 +76,7 @@ http_interactions:
|
|
76
76
|
- cloudflare
|
77
77
|
body:
|
78
78
|
encoding: ASCII-8BIT
|
79
|
-
string: '{"object":"user","id":"user_01H7TVSKS45SDHN5V9XPSM6H44","email":"willman@blips.app","email_verified":false,"first_name":"Jane","last_name":"Doe","created_at":"2023-08-14T20:28:58.929Z","updated_at":"2023-08-25T22:57:44.262Z","user_type":"unmanaged","email_verified_at":null,"google_oauth_profile_id":null,"microsoft_oauth_profile_id":null}'
|
79
|
+
string: '{"object":"user","id":"user_01H7TVSKS45SDHN5V9XPSM6H44","email":"willman@blips.app","email_verified":false,"first_name":"Jane","last_name":"Doe","external_id":"123","created_at":"2023-08-14T20:28:58.929Z","updated_at":"2023-08-25T22:57:44.262Z","user_type":"unmanaged","email_verified_at":null,"google_oauth_profile_id":null,"microsoft_oauth_profile_id":null}'
|
80
80
|
http_version:
|
81
81
|
recorded_at: Fri, 25 Aug 2023 23:37:04 GMT
|
82
82
|
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.21.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-
|
11
|
+
date: 2025-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: encryptor
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- lib/workos/invitation.rb
|
159
159
|
- lib/workos/magic_auth.rb
|
160
160
|
- lib/workos/mfa.rb
|
161
|
+
- lib/workos/oauth_tokens.rb
|
161
162
|
- lib/workos/organization.rb
|
162
163
|
- lib/workos/organization_membership.rb
|
163
164
|
- lib/workos/organizations.rb
|
@@ -196,6 +197,7 @@ files:
|
|
196
197
|
- spec/lib/workos/organizations_spec.rb
|
197
198
|
- spec/lib/workos/passwordless_spec.rb
|
198
199
|
- spec/lib/workos/portal_spec.rb
|
200
|
+
- spec/lib/workos/role_spec.rb
|
199
201
|
- spec/lib/workos/session_spec.rb
|
200
202
|
- spec/lib/workos/sso_spec.rb
|
201
203
|
- spec/lib/workos/user_management_spec.rb
|
@@ -300,6 +302,7 @@ files:
|
|
300
302
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/invalid.yml
|
301
303
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid.yml
|
302
304
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid_with_impersonator.yml
|
305
|
+
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid_with_oauth_tokens.yml
|
303
306
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_email_verification/invalid.yml
|
304
307
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_email_verification/valid.yml
|
305
308
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_magic_auth/invalid.yml
|
@@ -419,6 +422,7 @@ test_files:
|
|
419
422
|
- spec/lib/workos/organizations_spec.rb
|
420
423
|
- spec/lib/workos/passwordless_spec.rb
|
421
424
|
- spec/lib/workos/portal_spec.rb
|
425
|
+
- spec/lib/workos/role_spec.rb
|
422
426
|
- spec/lib/workos/session_spec.rb
|
423
427
|
- spec/lib/workos/sso_spec.rb
|
424
428
|
- spec/lib/workos/user_management_spec.rb
|
@@ -523,6 +527,7 @@ test_files:
|
|
523
527
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/invalid.yml
|
524
528
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid.yml
|
525
529
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid_with_impersonator.yml
|
530
|
+
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_code/valid_with_oauth_tokens.yml
|
526
531
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_email_verification/invalid.yml
|
527
532
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_email_verification/valid.yml
|
528
533
|
- spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_magic_auth/invalid.yml
|