workos 7.1.0 → 7.1.2

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.
@@ -6,6 +6,58 @@
6
6
 
7
7
  module WorkOS
8
8
  class UserManagement
9
+ class PasswordPlaintext
10
+ sig { returns(String) }
11
+ def password; end
12
+
13
+ sig do
14
+ params(
15
+ password: String
16
+ ).returns(WorkOS::UserManagement::PasswordPlaintext)
17
+ end
18
+ def self.new(password:); end
19
+ end
20
+
21
+ class PasswordHashed
22
+ sig { returns(String) }
23
+ def password_hash; end
24
+
25
+ sig { returns(String) }
26
+ def password_hash_type; end
27
+
28
+ sig do
29
+ params(
30
+ password_hash: String,
31
+ password_hash_type: String
32
+ ).returns(WorkOS::UserManagement::PasswordHashed)
33
+ end
34
+ def self.new(password_hash:, password_hash_type:); end
35
+ end
36
+
37
+ class RoleSingle
38
+ sig { returns(String) }
39
+ def role_slug; end
40
+
41
+ sig do
42
+ params(
43
+ role_slug: String
44
+ ).returns(WorkOS::UserManagement::RoleSingle)
45
+ end
46
+ def self.new(role_slug:); end
47
+ end
48
+
49
+ class RoleMultiple
50
+ sig { returns(T::Array[String]) }
51
+ def role_slugs; end
52
+
53
+ sig do
54
+ params(
55
+ role_slugs: T::Array[String]
56
+ ).returns(WorkOS::UserManagement::RoleMultiple)
57
+ end
58
+ def self.new(role_slugs:); end
59
+ end
60
+
9
61
  sig { params(client: WorkOS::BaseClient).void }
10
62
  def initialize(client); end
11
63
 
@@ -113,13 +165,11 @@ module WorkOS
113
165
  email_verified: T.nilable(T::Boolean),
114
166
  metadata: T.nilable(T::Hash[String, String]),
115
167
  external_id: T.nilable(String),
116
- password: T.nilable(String),
117
- password_hash: T.nilable(String),
118
- password_hash_type: T.nilable(String),
168
+ password: T.nilable(T.any(WorkOS::UserManagement::PasswordPlaintext, WorkOS::UserManagement::PasswordHashed)),
119
169
  request_options: T::Hash[Symbol, T.untyped]
120
170
  ).returns(WorkOS::User)
121
171
  end
122
- def create_user(email:, first_name:, last_name:, email_verified:, metadata:, external_id:, password:, password_hash:, password_hash_type:, request_options:); end
172
+ def create_user(email:, first_name:, last_name:, email_verified:, metadata:, external_id:, password:, request_options:); end
123
173
 
124
174
  sig do
125
175
  params(
@@ -147,13 +197,11 @@ module WorkOS
147
197
  metadata: T.nilable(T::Hash[String, String]),
148
198
  external_id: T.nilable(String),
149
199
  locale: T.nilable(String),
150
- password: T.nilable(String),
151
- password_hash: T.nilable(String),
152
- password_hash_type: T.nilable(String),
200
+ password: T.nilable(T.any(WorkOS::UserManagement::PasswordPlaintext, WorkOS::UserManagement::PasswordHashed)),
153
201
  request_options: T::Hash[Symbol, T.untyped]
154
202
  ).returns(WorkOS::User)
155
203
  end
156
- def update_user(id:, email:, first_name:, last_name:, email_verified:, metadata:, external_id:, locale:, password:, password_hash:, password_hash_type:, request_options:); end
204
+ def update_user(id:, email:, first_name:, last_name:, email_verified:, metadata:, external_id:, locale:, password:, request_options:); end
157
205
 
158
206
  sig do
159
207
  params(
@@ -328,12 +376,11 @@ module WorkOS
328
376
  params(
329
377
  user_id: String,
330
378
  organization_id: String,
331
- role_slug: T.nilable(String),
332
- role_slugs: T.nilable(T::Array[String]),
379
+ role: T.nilable(T.any(WorkOS::UserManagement::RoleSingle, WorkOS::UserManagement::RoleMultiple)),
333
380
  request_options: T::Hash[Symbol, T.untyped]
334
381
  ).returns(WorkOS::OrganizationMembership)
335
382
  end
336
- def create_organization_membership(user_id:, organization_id:, role_slug:, role_slugs:, request_options:); end
383
+ def create_organization_membership(user_id:, organization_id:, role:, request_options:); end
337
384
 
338
385
  sig do
339
386
  params(
@@ -346,12 +393,11 @@ module WorkOS
346
393
  sig do
347
394
  params(
348
395
  id: String,
349
- role_slug: T.nilable(String),
350
- role_slugs: T.nilable(T::Array[String]),
396
+ role: T.nilable(T.any(WorkOS::UserManagement::RoleSingle, WorkOS::UserManagement::RoleMultiple)),
351
397
  request_options: T::Hash[Symbol, T.untyped]
352
398
  ).returns(WorkOS::UserOrganizationMembership)
353
399
  end
354
- def update_organization_membership(id:, role_slug:, role_slugs:, request_options:); end
400
+ def update_organization_membership(id:, role:, request_options:); end
355
401
 
356
402
  sig do
357
403
  params(
@@ -42,7 +42,7 @@ class AuditLogsTest < Minitest::Test
42
42
  def test_create_schema_returns_expected_result
43
43
  stub_request(:post, %r{\Ahttps://api\.workos\.com/audit_logs/actions/stub/schemas(\?|\z)})
44
44
  .to_return(body: "{}", status: 200)
45
- result = @client.audit_logs.create_schema(action_name: "stub", targets: [])
45
+ result = @client.audit_logs.create_schema(action_name: "stub", targets: [{}])
46
46
  refute_nil result
47
47
  end
48
48
 
@@ -73,7 +73,7 @@ class AuditLogsTest < Minitest::Test
73
73
  {name: :update_organization_audit_logs_retention, verb: :put, url: %r{\Ahttps://api\.workos\.com/organizations/stub/audit_logs_retention(\?|\z)}, args: {id: "stub", retention_period_in_days: 1}},
74
74
  {name: :list_actions, verb: :get, url: %r{\Ahttps://api\.workos\.com/audit_logs/actions(\?|\z)}},
75
75
  {name: :list_action_schemas, verb: :get, url: %r{\Ahttps://api\.workos\.com/audit_logs/actions/stub/schemas(\?|\z)}, args: {action_name: "stub"}},
76
- {name: :create_schema, verb: :post, url: %r{\Ahttps://api\.workos\.com/audit_logs/actions/stub/schemas(\?|\z)}, args: {action_name: "stub", targets: []}},
76
+ {name: :create_schema, verb: :post, url: %r{\Ahttps://api\.workos\.com/audit_logs/actions/stub/schemas(\?|\z)}, args: {action_name: "stub", targets: [{}]}},
77
77
  {name: :create_event, verb: :post, url: %r{\Ahttps://api\.workos\.com/audit_logs/events(\?|\z)}, args: {organization_id: "stub", event: {}}},
78
78
  {name: :create_export, verb: :post, url: %r{\Ahttps://api\.workos\.com/audit_logs/exports(\?|\z)}, args: {organization_id: "stub", range_start: "stub", range_end: "stub"}},
79
79
  {name: :get_export, verb: :get, url: %r{\Ahttps://api\.workos\.com/audit_logs/exports/stub(\?|\z)}, args: {audit_log_export_id: "stub"}}
@@ -13,15 +13,31 @@ class AuthorizationTest < Minitest::Test
13
13
 
14
14
  def test_check_returns_expected_result
15
15
  stub_request(:post, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/check(\?|\z)})
16
+ .with(body: hash_including("permission_slug" => "stub", "resource_id" => "stub"))
16
17
  .to_return(body: "{}", status: 200)
17
- result = @client.authorization.check(organization_membership_id: "stub", permission_slug: "stub", resource_target: {type: "by_id"})
18
+ result = @client.authorization.check(organization_membership_id: "stub", permission_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetById.new(resource_id: "stub"))
19
+ refute_nil result
20
+ end
21
+
22
+ def test_check_with_resource_target_by_external_id_returns_expected_result
23
+ stub_request(:post, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/check(\?|\z)})
24
+ .with(body: hash_including("permission_slug" => "stub", "resource_external_id" => "stub", "resource_type_slug" => "stub"))
25
+ .to_return(body: "{}", status: 200)
26
+ result = @client.authorization.check(organization_membership_id: "stub", permission_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetByExternalId.new(resource_external_id: "stub", resource_type_slug: "stub"))
18
27
  refute_nil result
19
28
  end
20
29
 
21
30
  def test_list_resources_for_membership_returns_expected_result
22
31
  stub_request(:get, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/resources(\?|\z)})
23
32
  .to_return(body: '{"data": [], "list_metadata": {}}', status: 200)
24
- result = @client.authorization.list_resources_for_membership(organization_membership_id: "stub", permission_slug: "stub", parent_resource: {type: "by_id"})
33
+ result = @client.authorization.list_resources_for_membership(organization_membership_id: "stub", permission_slug: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub"))
34
+ assert_kind_of WorkOS::Types::ListStruct, result
35
+ end
36
+
37
+ def test_list_resources_for_membership_with_parent_resource_by_external_id_returns_expected_result
38
+ stub_request(:get, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/resources(\?|\z)})
39
+ .to_return(body: '{"data": [], "list_metadata": {}}', status: 200)
40
+ result = @client.authorization.list_resources_for_membership(organization_membership_id: "stub", permission_slug: "stub", parent_resource: WorkOS::Authorization::ParentResourceByExternalId.new(parent_resource_type_slug: "stub", parent_resource_external_id: "stub"))
25
41
  assert_kind_of WorkOS::Types::ListStruct, result
26
42
  end
27
43
 
@@ -48,15 +64,31 @@ class AuthorizationTest < Minitest::Test
48
64
 
49
65
  def test_assign_role_returns_expected_result
50
66
  stub_request(:post, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)})
67
+ .with(body: hash_including("role_slug" => "stub", "resource_id" => "stub"))
51
68
  .to_return(body: "{}", status: 200)
52
- result = @client.authorization.assign_role(organization_membership_id: "stub", role_slug: "stub", resource_target: {type: "by_id"})
69
+ result = @client.authorization.assign_role(organization_membership_id: "stub", role_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetById.new(resource_id: "stub"))
70
+ refute_nil result
71
+ end
72
+
73
+ def test_assign_role_with_resource_target_by_external_id_returns_expected_result
74
+ stub_request(:post, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)})
75
+ .with(body: hash_including("role_slug" => "stub", "resource_external_id" => "stub", "resource_type_slug" => "stub"))
76
+ .to_return(body: "{}", status: 200)
77
+ result = @client.authorization.assign_role(organization_membership_id: "stub", role_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetByExternalId.new(resource_external_id: "stub", resource_type_slug: "stub"))
53
78
  refute_nil result
54
79
  end
55
80
 
56
81
  def test_remove_role_returns_expected_result
57
82
  stub_request(:delete, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)})
58
83
  .to_return(body: "{}", status: 200)
59
- result = @client.authorization.remove_role(organization_membership_id: "stub", role_slug: "stub", resource_target: {type: "by_id"})
84
+ result = @client.authorization.remove_role(organization_membership_id: "stub", role_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetById.new(resource_id: "stub"))
85
+ assert_nil result
86
+ end
87
+
88
+ def test_remove_role_with_resource_target_by_external_id_returns_expected_result
89
+ stub_request(:delete, %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)})
90
+ .to_return(body: "{}", status: 200)
91
+ result = @client.authorization.remove_role(organization_membership_id: "stub", role_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetByExternalId.new(resource_external_id: "stub", resource_type_slug: "stub"))
60
92
  assert_nil result
61
93
  end
62
94
 
@@ -112,7 +144,7 @@ class AuthorizationTest < Minitest::Test
112
144
  def test_set_organization_role_permissions_returns_expected_result
113
145
  stub_request(:put, %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles/stub/permissions(\?|\z)})
114
146
  .to_return(body: "{}", status: 200)
115
- result = @client.authorization.set_organization_role_permissions(organization_id: "stub", slug: "stub", permissions: [])
147
+ result = @client.authorization.set_organization_role_permissions(organization_id: "stub", slug: "stub", permissions: ["stub"])
116
148
  refute_nil result
117
149
  end
118
150
 
@@ -132,8 +164,17 @@ class AuthorizationTest < Minitest::Test
132
164
 
133
165
  def test_update_resource_by_external_id_returns_expected_result
134
166
  stub_request(:patch, %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/resources/stub/stub(\?|\z)})
167
+ .with(body: hash_including("parent_resource_id" => "stub"))
135
168
  .to_return(body: "{}", status: 200)
136
- result = @client.authorization.update_resource_by_external_id(organization_id: "stub", resource_type_slug: "stub", external_id: "stub")
169
+ result = @client.authorization.update_resource_by_external_id(organization_id: "stub", resource_type_slug: "stub", external_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub"))
170
+ refute_nil result
171
+ end
172
+
173
+ def test_update_resource_by_external_id_with_parent_resource_by_external_id_returns_expected_result
174
+ stub_request(:patch, %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/resources/stub/stub(\?|\z)})
175
+ .with(body: hash_including("parent_resource_external_id" => "stub", "parent_resource_type_slug" => "stub"))
176
+ .to_return(body: "{}", status: 200)
177
+ result = @client.authorization.update_resource_by_external_id(organization_id: "stub", resource_type_slug: "stub", external_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceByExternalId.new(parent_resource_external_id: "stub", parent_resource_type_slug: "stub"))
137
178
  refute_nil result
138
179
  end
139
180
 
@@ -154,14 +195,30 @@ class AuthorizationTest < Minitest::Test
154
195
  def test_list_resources_returns_expected_result
155
196
  stub_request(:get, %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)})
156
197
  .to_return(body: '{"data": [], "list_metadata": {}}', status: 200)
157
- result = @client.authorization.list_resources
198
+ result = @client.authorization.list_resources(parent: WorkOS::Authorization::ParentById.new(parent_resource_id: "stub"))
199
+ assert_kind_of WorkOS::Types::ListStruct, result
200
+ end
201
+
202
+ def test_list_resources_with_parent_by_external_id_returns_expected_result
203
+ stub_request(:get, %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)})
204
+ .to_return(body: '{"data": [], "list_metadata": {}}', status: 200)
205
+ result = @client.authorization.list_resources(parent: WorkOS::Authorization::ParentByExternalId.new(parent_resource_type_slug: "stub", parent_external_id: "stub"))
158
206
  assert_kind_of WorkOS::Types::ListStruct, result
159
207
  end
160
208
 
161
209
  def test_create_resource_returns_expected_result
162
210
  stub_request(:post, %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)})
211
+ .with(body: hash_including("external_id" => "stub", "name" => "stub", "resource_type_slug" => "stub", "organization_id" => "stub", "parent_resource_id" => "stub"))
163
212
  .to_return(body: "{}", status: 200)
164
- result = @client.authorization.create_resource(external_id: "stub", name: "stub", resource_type_slug: "stub", organization_id: "stub")
213
+ result = @client.authorization.create_resource(external_id: "stub", name: "stub", resource_type_slug: "stub", organization_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub"))
214
+ refute_nil result
215
+ end
216
+
217
+ def test_create_resource_with_parent_resource_by_external_id_returns_expected_result
218
+ stub_request(:post, %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)})
219
+ .with(body: hash_including("external_id" => "stub", "name" => "stub", "resource_type_slug" => "stub", "organization_id" => "stub", "parent_resource_external_id" => "stub", "parent_resource_type_slug" => "stub"))
220
+ .to_return(body: "{}", status: 200)
221
+ result = @client.authorization.create_resource(external_id: "stub", name: "stub", resource_type_slug: "stub", organization_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceByExternalId.new(parent_resource_external_id: "stub", parent_resource_type_slug: "stub"))
165
222
  refute_nil result
166
223
  end
167
224
 
@@ -174,8 +231,17 @@ class AuthorizationTest < Minitest::Test
174
231
 
175
232
  def test_update_resource_returns_expected_result
176
233
  stub_request(:patch, %r{\Ahttps://api\.workos\.com/authorization/resources/stub(\?|\z)})
234
+ .with(body: hash_including("parent_resource_id" => "stub"))
235
+ .to_return(body: "{}", status: 200)
236
+ result = @client.authorization.update_resource(resource_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub"))
237
+ refute_nil result
238
+ end
239
+
240
+ def test_update_resource_with_parent_resource_by_external_id_returns_expected_result
241
+ stub_request(:patch, %r{\Ahttps://api\.workos\.com/authorization/resources/stub(\?|\z)})
242
+ .with(body: hash_including("parent_resource_external_id" => "stub", "parent_resource_type_slug" => "stub"))
177
243
  .to_return(body: "{}", status: 200)
178
- result = @client.authorization.update_resource(resource_id: "stub")
244
+ result = @client.authorization.update_resource(resource_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceByExternalId.new(parent_resource_external_id: "stub", parent_resource_type_slug: "stub"))
179
245
  refute_nil result
180
246
  end
181
247
 
@@ -231,7 +297,7 @@ class AuthorizationTest < Minitest::Test
231
297
  def test_set_environment_role_permissions_returns_expected_result
232
298
  stub_request(:put, %r{\Ahttps://api\.workos\.com/authorization/roles/stub/permissions(\?|\z)})
233
299
  .to_return(body: "{}", status: 200)
234
- result = @client.authorization.set_environment_role_permissions(slug: "stub", permissions: [])
300
+ result = @client.authorization.set_environment_role_permissions(slug: "stub", permissions: ["stub"])
235
301
  refute_nil result
236
302
  end
237
303
 
@@ -272,13 +338,13 @@ class AuthorizationTest < Minitest::Test
272
338
 
273
339
  # Parameterized authentication error tests (one per endpoint).
274
340
  [
275
- {name: :check, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/check(\?|\z)}, args: {organization_membership_id: "stub", permission_slug: "stub", resource_target: {type: "by_id"}}},
276
- {name: :list_resources_for_membership, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/resources(\?|\z)}, args: {organization_membership_id: "stub", permission_slug: "stub", parent_resource: {type: "by_id"}}},
341
+ {name: :check, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/check(\?|\z)}, args: {organization_membership_id: "stub", permission_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetById.new(resource_id: "stub")}},
342
+ {name: :list_resources_for_membership, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/resources(\?|\z)}, args: {organization_membership_id: "stub", permission_slug: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub")}},
277
343
  {name: :list_effective_permissions, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/resources/stub/permissions(\?|\z)}, args: {organization_membership_id: "stub", resource_id: "stub"}},
278
344
  {name: :list_effective_permissions_by_external_id, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/resources/stub/stub/permissions(\?|\z)}, args: {organization_membership_id: "stub", resource_type_slug: "stub", external_id: "stub"}},
279
345
  {name: :list_role_assignments, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)}, args: {organization_membership_id: "stub"}},
280
- {name: :assign_role, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)}, args: {organization_membership_id: "stub", role_slug: "stub", resource_target: {type: "by_id"}}},
281
- {name: :remove_role, verb: :delete, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)}, args: {organization_membership_id: "stub", role_slug: "stub", resource_target: {type: "by_id"}}},
346
+ {name: :assign_role, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)}, args: {organization_membership_id: "stub", role_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetById.new(resource_id: "stub")}},
347
+ {name: :remove_role, verb: :delete, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments(\?|\z)}, args: {organization_membership_id: "stub", role_slug: "stub", resource_target: WorkOS::Authorization::ResourceTargetById.new(resource_id: "stub")}},
282
348
  {name: :remove_role_assignment, verb: :delete, url: %r{\Ahttps://api\.workos\.com/authorization/organization_memberships/stub/role_assignments/stub(\?|\z)}, args: {organization_membership_id: "stub", role_assignment_id: "stub"}},
283
349
  {name: :list_organization_roles, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles(\?|\z)}, args: {organization_id: "stub"}},
284
350
  {name: :create_organization_role, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles(\?|\z)}, args: {organization_id: "stub", name: "stub"}},
@@ -286,16 +352,16 @@ class AuthorizationTest < Minitest::Test
286
352
  {name: :update_organization_role, verb: :patch, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles/stub(\?|\z)}, args: {organization_id: "stub", slug: "stub"}},
287
353
  {name: :delete_organization_role, verb: :delete, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles/stub(\?|\z)}, args: {organization_id: "stub", slug: "stub"}},
288
354
  {name: :add_organization_role_permission, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles/stub/permissions(\?|\z)}, args: {organization_id: "stub", slug: "stub", body_slug: "stub"}},
289
- {name: :set_organization_role_permissions, verb: :put, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles/stub/permissions(\?|\z)}, args: {organization_id: "stub", slug: "stub", permissions: []}},
355
+ {name: :set_organization_role_permissions, verb: :put, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles/stub/permissions(\?|\z)}, args: {organization_id: "stub", slug: "stub", permissions: ["stub"]}},
290
356
  {name: :remove_organization_role_permission, verb: :delete, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/roles/stub/permissions/stub(\?|\z)}, args: {organization_id: "stub", slug: "stub", permission_slug: "stub"}},
291
357
  {name: :get_resource_by_external_id, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/resources/stub/stub(\?|\z)}, args: {organization_id: "stub", resource_type_slug: "stub", external_id: "stub"}},
292
- {name: :update_resource_by_external_id, verb: :patch, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/resources/stub/stub(\?|\z)}, args: {organization_id: "stub", resource_type_slug: "stub", external_id: "stub"}},
358
+ {name: :update_resource_by_external_id, verb: :patch, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/resources/stub/stub(\?|\z)}, args: {organization_id: "stub", resource_type_slug: "stub", external_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub")}},
293
359
  {name: :delete_resource_by_external_id, verb: :delete, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/resources/stub/stub(\?|\z)}, args: {organization_id: "stub", resource_type_slug: "stub", external_id: "stub"}},
294
360
  {name: :list_memberships_for_resource_by_external_id, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/organizations/stub/resources/stub/stub/organization_memberships(\?|\z)}, args: {organization_id: "stub", resource_type_slug: "stub", external_id: "stub", permission_slug: "stub"}},
295
- {name: :list_resources, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)}},
296
- {name: :create_resource, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)}, args: {external_id: "stub", name: "stub", resource_type_slug: "stub", organization_id: "stub"}},
361
+ {name: :list_resources, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)}, args: {parent: WorkOS::Authorization::ParentById.new(parent_resource_id: "stub")}},
362
+ {name: :create_resource, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/resources(\?|\z)}, args: {external_id: "stub", name: "stub", resource_type_slug: "stub", organization_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub")}},
297
363
  {name: :get_resource, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/resources/stub(\?|\z)}, args: {resource_id: "stub"}},
298
- {name: :update_resource, verb: :patch, url: %r{\Ahttps://api\.workos\.com/authorization/resources/stub(\?|\z)}, args: {resource_id: "stub"}},
364
+ {name: :update_resource, verb: :patch, url: %r{\Ahttps://api\.workos\.com/authorization/resources/stub(\?|\z)}, args: {resource_id: "stub", parent_resource: WorkOS::Authorization::ParentResourceById.new(parent_resource_id: "stub")}},
299
365
  {name: :delete_resource, verb: :delete, url: %r{\Ahttps://api\.workos\.com/authorization/resources/stub(\?|\z)}, args: {resource_id: "stub"}},
300
366
  {name: :list_memberships_for_resource, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/resources/stub/organization_memberships(\?|\z)}, args: {resource_id: "stub", permission_slug: "stub"}},
301
367
  {name: :list_environment_roles, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/roles(\?|\z)}},
@@ -303,7 +369,7 @@ class AuthorizationTest < Minitest::Test
303
369
  {name: :get_environment_role, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/roles/stub(\?|\z)}, args: {slug: "stub"}},
304
370
  {name: :update_environment_role, verb: :patch, url: %r{\Ahttps://api\.workos\.com/authorization/roles/stub(\?|\z)}, args: {slug: "stub"}},
305
371
  {name: :add_environment_role_permission, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/roles/stub/permissions(\?|\z)}, args: {slug: "stub", body_slug: "stub"}},
306
- {name: :set_environment_role_permissions, verb: :put, url: %r{\Ahttps://api\.workos\.com/authorization/roles/stub/permissions(\?|\z)}, args: {slug: "stub", permissions: []}},
372
+ {name: :set_environment_role_permissions, verb: :put, url: %r{\Ahttps://api\.workos\.com/authorization/roles/stub/permissions(\?|\z)}, args: {slug: "stub", permissions: ["stub"]}},
307
373
  {name: :list_permissions, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/permissions(\?|\z)}},
308
374
  {name: :create_permission, verb: :post, url: %r{\Ahttps://api\.workos\.com/authorization/permissions(\?|\z)}, args: {slug: "stub", name: "stub"}},
309
375
  {name: :get_permission, verb: :get, url: %r{\Ahttps://api\.workos\.com/authorization/permissions/stub(\?|\z)}, args: {slug: "stub"}},
@@ -3,6 +3,9 @@
3
3
  # @oagen-ignore-file
4
4
  require "test_helper"
5
5
  require "base64"
6
+ require "json"
7
+ require "openssl"
8
+ require "securerandom"
6
9
 
7
10
  class EncryptorsAesGcmTest < Minitest::Test
8
11
  PASSWORD = "test-cookie-password-at-least-32"
@@ -51,4 +54,22 @@ class EncryptorsAesGcmTest < Minitest::Test
51
54
  sealed2 = @enc.seal(data, PASSWORD)
52
55
  refute_equal sealed1, sealed2
53
56
  end
57
+
58
+ def test_unseal_reads_legacy_v6_payload
59
+ data = {"access_token" => "tok_abc", "refresh_token" => "ref_xyz"}
60
+ sealed = legacy_v6_seal(data, PASSWORD)
61
+ assert_equal data, @enc.unseal(sealed, PASSWORD)
62
+ end
63
+
64
+ private
65
+
66
+ def legacy_v6_seal(data, key)
67
+ cipher = OpenSSL::Cipher.new("aes-256-gcm").encrypt
68
+ iv = SecureRandom.random_bytes(12)
69
+ cipher.key = key
70
+ cipher.iv = iv
71
+ ciphertext = cipher.update(JSON.generate(data)) + cipher.final
72
+
73
+ Base64.encode64(iv + ciphertext + cipher.auth_tag)
74
+ end
54
75
  end
@@ -6,6 +6,7 @@ require "json"
6
6
  require "openssl"
7
7
  require "jwt"
8
8
  require "base64"
9
+ require "securerandom"
9
10
 
10
11
  class SessionTest < Minitest::Test
11
12
  PASSWORD = "very-long-cookie-password-secret"
@@ -84,6 +85,22 @@ class SessionTest < Minitest::Test
84
85
  assert_equal "u_1", result.user["id"]
85
86
  end
86
87
 
88
+ def test_authenticate_reads_legacy_v6_sealed_session
89
+ rsa, pub = signing_key_pair
90
+ access_token = make_jwt({"sid" => "session_v6", "org_id" => "org_legacy", "exp" => Time.now.to_i + 60}, rsa)
91
+ sealed = legacy_v6_seal({"access_token" => access_token, "user" => {"id" => "u_legacy"}}, PASSWORD)
92
+
93
+ stub_request(:get, "https://api.workos.com/sso/jwks/client_001")
94
+ .to_return(status: 200, body: jwks_payload(pub).to_json)
95
+
96
+ result = @sm.authenticate(seal_data: sealed, cookie_password: PASSWORD)
97
+ assert_kind_of WorkOS::SessionManager::AuthSuccess, result
98
+ assert result.authenticated
99
+ assert_equal "session_v6", result.session_id
100
+ assert_equal "org_legacy", result.organization_id
101
+ assert_equal "u_legacy", result.user["id"]
102
+ end
103
+
87
104
  def test_authenticate_merges_custom_claims_from_block
88
105
  rsa, pub = signing_key_pair
89
106
  access_token = make_jwt(
@@ -206,6 +223,170 @@ class SessionTest < Minitest::Test
206
223
  assert_equal "https://app/cb", params["return_to"]
207
224
  end
208
225
 
226
+ # --- Session#refresh -------------------------------------------------------
227
+
228
+ def test_refresh_seals_session_client_side_and_returns_refresh_success
229
+ rsa, pub = signing_key_pair
230
+ old_access = make_jwt({"sid" => "session_old", "exp" => Time.now.to_i - 60}, rsa)
231
+ sealed = @sm.seal_data({"access_token" => old_access, "refresh_token" => "rt_old", "user" => {"id" => "u_1"}}, PASSWORD)
232
+
233
+ new_access = make_jwt({"sid" => "session_new", "org_id" => "org_1", "role" => "admin", "exp" => Time.now.to_i + 300}, rsa)
234
+ api_response = {
235
+ "access_token" => new_access,
236
+ "refresh_token" => "rt_new",
237
+ "user" => {"id" => "u_1", "email" => "a@b.com"},
238
+ "impersonator" => nil
239
+ }
240
+
241
+ stub_request(:post, "https://api.workos.com/user_management/authenticate")
242
+ .with(body: hash_including("grant_type" => "refresh_token", "refresh_token" => "rt_old"))
243
+ .to_return(status: 200, body: api_response.to_json)
244
+ stub_request(:get, "https://api.workos.com/sso/jwks/client_001")
245
+ .to_return(status: 200, body: jwks_payload(pub).to_json)
246
+
247
+ session = @sm.load(seal_data: sealed, cookie_password: PASSWORD)
248
+ result = session.refresh
249
+
250
+ assert_kind_of WorkOS::SessionManager::RefreshSuccess, result
251
+ assert result.authenticated
252
+ assert_equal "session_new", result.session_id
253
+ assert_equal "org_1", result.organization_id
254
+ assert_equal "admin", result.role
255
+ assert_equal "u_1", result.user["id"]
256
+
257
+ # sealed_session should be a non-empty string that round-trips
258
+ refute_empty result.sealed_session
259
+ unsealed = @sm.unseal_data(result.sealed_session, PASSWORD)
260
+ assert_equal new_access, unsealed["access_token"]
261
+ assert_equal "rt_new", unsealed["refresh_token"]
262
+ end
263
+
264
+ def test_refresh_reads_legacy_v6_sealed_session
265
+ rsa, pub = signing_key_pair
266
+ old_access = make_jwt({"sid" => "session_old_v6", "exp" => Time.now.to_i - 60}, rsa)
267
+ sealed = legacy_v6_seal(
268
+ {"access_token" => old_access, "refresh_token" => "rt_old_v6", "user" => {"id" => "u_v6"}},
269
+ PASSWORD
270
+ )
271
+
272
+ new_access = make_jwt({"sid" => "session_new_v6", "org_id" => "org_v6", "role" => "member", "exp" => Time.now.to_i + 300}, rsa)
273
+ api_response = {
274
+ "access_token" => new_access,
275
+ "refresh_token" => "rt_new_v6",
276
+ "user" => {"id" => "u_v6", "email" => "legacy@example.com"},
277
+ "impersonator" => nil
278
+ }
279
+
280
+ stub_request(:post, "https://api.workos.com/user_management/authenticate")
281
+ .with(body: hash_including("grant_type" => "refresh_token", "refresh_token" => "rt_old_v6"))
282
+ .to_return(status: 200, body: api_response.to_json)
283
+ stub_request(:get, "https://api.workos.com/sso/jwks/client_001")
284
+ .to_return(status: 200, body: jwks_payload(pub).to_json)
285
+
286
+ session = @sm.load(seal_data: sealed, cookie_password: PASSWORD)
287
+ result = session.refresh
288
+
289
+ assert_kind_of WorkOS::SessionManager::RefreshSuccess, result
290
+ assert result.authenticated
291
+ assert_equal "session_new_v6", result.session_id
292
+ assert_equal "org_v6", result.organization_id
293
+ assert_equal "member", result.role
294
+ assert_equal "u_v6", result.user["id"]
295
+
296
+ refute_empty result.sealed_session
297
+ unsealed = @sm.unseal_data(result.sealed_session, PASSWORD)
298
+ assert_equal new_access, unsealed["access_token"]
299
+ assert_equal "rt_new_v6", unsealed["refresh_token"]
300
+ assert_equal "u_v6", unsealed["user"]["id"]
301
+ end
302
+
303
+ def test_refresh_updates_internal_seal_data_for_subsequent_authenticate
304
+ rsa, pub = signing_key_pair
305
+ old_access = make_jwt({"sid" => "session_old", "exp" => Time.now.to_i - 60}, rsa)
306
+ sealed = @sm.seal_data({"access_token" => old_access, "refresh_token" => "rt_old", "user" => {"id" => "u_1"}}, PASSWORD)
307
+
308
+ new_access = make_jwt({"sid" => "session_refreshed", "org_id" => "org_2", "exp" => Time.now.to_i + 300}, rsa)
309
+ api_response = {
310
+ "access_token" => new_access,
311
+ "refresh_token" => "rt_new",
312
+ "user" => {"id" => "u_1"}
313
+ }
314
+
315
+ stub_request(:post, "https://api.workos.com/user_management/authenticate")
316
+ .to_return(status: 200, body: api_response.to_json)
317
+ stub_request(:get, "https://api.workos.com/sso/jwks/client_001")
318
+ .to_return(status: 200, body: jwks_payload(pub).to_json)
319
+
320
+ session = @sm.load(seal_data: sealed, cookie_password: PASSWORD)
321
+ session.refresh
322
+
323
+ # A subsequent authenticate should use the refreshed token
324
+ auth = session.authenticate
325
+ assert_kind_of WorkOS::SessionManager::AuthSuccess, auth
326
+ assert auth.authenticated
327
+ assert_equal "session_refreshed", auth.session_id
328
+ end
329
+
330
+ def test_refresh_returns_error_on_invalid_cookie
331
+ result = @sm.refresh(seal_data: "garbage", cookie_password: PASSWORD)
332
+ assert_kind_of WorkOS::SessionManager::RefreshError, result
333
+ refute result.authenticated
334
+ assert_equal WorkOS::SessionManager::INVALID_SESSION_COOKIE, result.reason
335
+ end
336
+
337
+ def test_refresh_returns_error_when_no_refresh_token
338
+ sealed = @sm.seal_data({"access_token" => "at_only"}, PASSWORD)
339
+ result = @sm.refresh(seal_data: sealed, cookie_password: PASSWORD)
340
+ assert_kind_of WorkOS::SessionManager::RefreshError, result
341
+ assert_equal WorkOS::SessionManager::INVALID_SESSION_COOKIE, result.reason
342
+ end
343
+
344
+ def test_refresh_does_not_send_session_param_to_api
345
+ rsa, pub = signing_key_pair
346
+ old_access = make_jwt({"sid" => "s", "exp" => Time.now.to_i - 60}, rsa)
347
+ sealed = @sm.seal_data({"access_token" => old_access, "refresh_token" => "rt_x", "user" => {"id" => "u"}}, PASSWORD)
348
+
349
+ new_access = make_jwt({"sid" => "s2", "exp" => Time.now.to_i + 300}, rsa)
350
+ api_response = {"access_token" => new_access, "refresh_token" => "rt_y", "user" => {"id" => "u"}}
351
+
352
+ stub = stub_request(:post, "https://api.workos.com/user_management/authenticate")
353
+ .with { |req| !req.body.include?("seal_session") }
354
+ .to_return(status: 200, body: api_response.to_json)
355
+ stub_request(:get, "https://api.workos.com/sso/jwks/client_001")
356
+ .to_return(status: 200, body: jwks_payload(pub).to_json)
357
+
358
+ session = @sm.load(seal_data: sealed, cookie_password: PASSWORD)
359
+ session.refresh
360
+
361
+ assert_requested(stub)
362
+ end
363
+
364
+ def test_refresh_returns_error_on_malformed_access_token_without_mutating_state
365
+ rsa, pub = signing_key_pair
366
+ old_access = make_jwt({"sid" => "session_old", "exp" => Time.now.to_i - 60}, rsa)
367
+ sealed = @sm.seal_data({"access_token" => old_access, "refresh_token" => "rt_old", "user" => {"id" => "u_1"}}, PASSWORD)
368
+
369
+ api_response = {
370
+ "access_token" => "not-a-valid-jwt",
371
+ "refresh_token" => "rt_new",
372
+ "user" => {"id" => "u_1"}
373
+ }
374
+
375
+ stub_request(:post, "https://api.workos.com/user_management/authenticate")
376
+ .to_return(status: 200, body: api_response.to_json)
377
+ stub_request(:get, "https://api.workos.com/sso/jwks/client_001")
378
+ .to_return(status: 200, body: jwks_payload(pub).to_json)
379
+
380
+ session = @sm.load(seal_data: sealed, cookie_password: PASSWORD)
381
+ result = session.refresh
382
+
383
+ assert_kind_of WorkOS::SessionManager::RefreshError, result
384
+ refute result.authenticated
385
+
386
+ # Session state should not have been mutated
387
+ assert_equal sealed, session.seal_data
388
+ end
389
+
209
390
  # --- Session constructor validation ---------------------------------------
210
391
 
211
392
  def test_session_load_requires_cookie_password
@@ -258,4 +439,16 @@ class SessionTest < Minitest::Test
258
439
  assert_kind_of WorkOS::SessionManager::AuthSuccess, result
259
440
  assert_equal "s_custom", result.session_id
260
441
  end
442
+
443
+ private
444
+
445
+ def legacy_v6_seal(data, key)
446
+ cipher = OpenSSL::Cipher.new("aes-256-gcm").encrypt
447
+ iv = SecureRandom.random_bytes(12)
448
+ cipher.key = key
449
+ cipher.iv = iv
450
+ ciphertext = cipher.update(JSON.generate(data)) + cipher.final
451
+
452
+ Base64.encode64(iv + ciphertext + cipher.auth_tag)
453
+ end
261
454
  end