descope 1.1.0 → 1.2.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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +4 -4
  3. data/.github/workflows/publish-gem.yaml +2 -2
  4. data/.github/workflows/release-please.yaml +1 -1
  5. data/.release-please-manifest.json +1 -1
  6. data/.rubocop.yml +1 -1
  7. data/.rubocop_todo.yml +1 -1
  8. data/.ruby-version +1 -1
  9. data/CHANGELOG.md +10 -0
  10. data/Gemfile +5 -5
  11. data/Gemfile.lock +32 -32
  12. data/README.md +233 -1
  13. data/lib/descope/api/v1/auth/enchantedlink.rb +76 -9
  14. data/lib/descope/api/v1/management/access_key.rb +8 -7
  15. data/lib/descope/api/v1/management/analytics.rb +62 -0
  16. data/lib/descope/api/v1/management/audit.rb +2 -2
  17. data/lib/descope/api/v1/management/authz.rb +15 -15
  18. data/lib/descope/api/v1/management/common.rb +76 -0
  19. data/lib/descope/api/v1/management/descoper.rb +45 -0
  20. data/lib/descope/api/v1/management/engine.rb +44 -0
  21. data/lib/descope/api/v1/management/fga.rb +64 -0
  22. data/lib/descope/api/v1/management/flow.rb +5 -5
  23. data/lib/descope/api/v1/management/group.rb +42 -0
  24. data/lib/descope/api/v1/management/jwt_template.rb +49 -0
  25. data/lib/descope/api/v1/management/lists.rb +96 -0
  26. data/lib/descope/api/v1/management/management_key.rb +54 -0
  27. data/lib/descope/api/v1/management/outbound_app.rb +112 -0
  28. data/lib/descope/api/v1/management/password.rb +2 -2
  29. data/lib/descope/api/v1/management/permission.rb +4 -4
  30. data/lib/descope/api/v1/management/project.rb +5 -5
  31. data/lib/descope/api/v1/management/role.rb +5 -5
  32. data/lib/descope/api/v1/management/scim.rb +14 -14
  33. data/lib/descope/api/v1/management/scope_claim_mapping.rb +34 -0
  34. data/lib/descope/api/v1/management/sso_application.rb +7 -7
  35. data/lib/descope/api/v1/management/sso_settings.rb +5 -5
  36. data/lib/descope/api/v1/management/tenant.rb +8 -6
  37. data/lib/descope/api/v1/management/third_party_application.rb +190 -0
  38. data/lib/descope/api/v1/management/user.rb +36 -36
  39. data/lib/descope/api/v1/management.rb +22 -0
  40. data/lib/descope/http_client.rb +30 -0
  41. data/lib/descope/mixins/common.rb +1 -0
  42. data/lib/descope/mixins/http.rb +23 -16
  43. data/lib/descope/mixins/initializer.rb +19 -9
  44. data/lib/descope/mixins/requests.rb +24 -0
  45. data/lib/descope/mixins.rb +2 -1
  46. data/lib/descope/version.rb +1 -1
  47. data/spec/integration/lib.descope/api/v1/management/user_spec.rb +1 -1
  48. data/spec/lib.descope/api/v1/auth/enchantedlink_spec.rb +163 -1
  49. data/spec/lib.descope/api/v1/management/access_key_spec.rb +7 -7
  50. data/spec/lib.descope/api/v1/management/analytics_spec.rb +82 -0
  51. data/spec/lib.descope/api/v1/management/audit_spec.rb +2 -2
  52. data/spec/lib.descope/api/v1/management/authz_spec.rb +16 -16
  53. data/spec/lib.descope/api/v1/management/descoper_spec.rb +101 -0
  54. data/spec/lib.descope/api/v1/management/engine_spec.rb +115 -0
  55. data/spec/lib.descope/api/v1/management/fga_spec.rb +169 -0
  56. data/spec/lib.descope/api/v1/management/flow_spec.rb +5 -5
  57. data/spec/lib.descope/api/v1/management/group_spec.rb +72 -0
  58. data/spec/lib.descope/api/v1/management/jwt_template_spec.rb +103 -0
  59. data/spec/lib.descope/api/v1/management/lists_spec.rb +285 -0
  60. data/spec/lib.descope/api/v1/management/management_key_spec.rb +109 -0
  61. data/spec/lib.descope/api/v1/management/outbound_app_spec.rb +236 -0
  62. data/spec/lib.descope/api/v1/management/password_spec.rb +2 -2
  63. data/spec/lib.descope/api/v1/management/permission_spec.rb +4 -4
  64. data/spec/lib.descope/api/v1/management/project_spec.rb +4 -4
  65. data/spec/lib.descope/api/v1/management/role_spec.rb +5 -5
  66. data/spec/lib.descope/api/v1/management/scim_spec.rb +14 -14
  67. data/spec/lib.descope/api/v1/management/scope_claim_mapping_spec.rb +59 -0
  68. data/spec/lib.descope/api/v1/management/sso_application_spec.rb +6 -6
  69. data/spec/lib.descope/api/v1/management/sso_settings_spec.rb +5 -5
  70. data/spec/lib.descope/api/v1/management/tenant_spec.rb +6 -6
  71. data/spec/lib.descope/api/v1/management/third_party_application_spec.rb +171 -0
  72. data/spec/lib.descope/api/v1/management/user_spec.rb +36 -36
  73. data/spec/lib.descope/auth_management_key_spec.rb +151 -0
  74. data/spec/support/client_config.rb +1 -0
  75. data/spec/support/dummy_class.rb +12 -9
  76. metadata +28 -3
@@ -15,7 +15,7 @@ describe Descope::Api::V1::Management::Tenant do
15
15
  end
16
16
 
17
17
  it 'is expected to create a new tenant' do
18
- expect(@instance).to receive(:post).with(
18
+ expect(@instance).to receive(:mgmt_post).with(
19
19
  TENANT_CREATE_PATH, {
20
20
  name: 'test',
21
21
  id: 'test',
@@ -46,7 +46,7 @@ describe Descope::Api::V1::Management::Tenant do
46
46
  end
47
47
 
48
48
  it 'is expected to update a tenant' do
49
- expect(@instance).to receive(:post).with(
49
+ expect(@instance).to receive(:mgmt_post).with(
50
50
  TENANT_UPDATE_PATH, {
51
51
  name: 'test',
52
52
  id: 'test',
@@ -77,7 +77,7 @@ describe Descope::Api::V1::Management::Tenant do
77
77
  end
78
78
 
79
79
  it 'is expected to delete a tenant' do
80
- expect(@instance).to receive(:post).with(
80
+ expect(@instance).to receive(:mgmt_post).with(
81
81
  TENANT_DELETE_PATH, { id: 'test' }
82
82
  )
83
83
  expect { @instance.delete_tenant('test') }.not_to raise_error
@@ -90,7 +90,7 @@ describe Descope::Api::V1::Management::Tenant do
90
90
  end
91
91
 
92
92
  it 'is expected to load a tenant' do
93
- expect(@instance).to receive(:get).with(
93
+ expect(@instance).to receive(:mgmt_get).with(
94
94
  TENANT_LOAD_PATH, { id: 'test' }
95
95
  )
96
96
  expect { @instance.load_tenant('test') }.not_to raise_error
@@ -103,7 +103,7 @@ describe Descope::Api::V1::Management::Tenant do
103
103
  end
104
104
 
105
105
  it 'is expected to load all tenants' do
106
- expect(@instance).to receive(:get).with(TENANT_LOAD_ALL_PATH)
106
+ expect(@instance).to receive(:mgmt_get).with(TENANT_LOAD_ALL_PATH)
107
107
  expect { @instance.load_all_tenants }.not_to raise_error
108
108
  end
109
109
  end
@@ -114,7 +114,7 @@ describe Descope::Api::V1::Management::Tenant do
114
114
  end
115
115
 
116
116
  it 'is expected to search all tenants' do
117
- expect(@instance).to receive(:post).with(
117
+ expect(@instance).to receive(:mgmt_post).with(
118
118
  TENANT_SEARCH_ALL_PATH, {
119
119
  ids: %w[test1 test2],
120
120
  names: %w[test1 test2],
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Descope::Api::V1::Management::ThirdPartyApplication do
6
+ before(:all) do
7
+ dummy_instance = DummyClass.new
8
+ dummy_instance.extend(Descope::Api::V1::Management::ThirdPartyApplication)
9
+ @instance = dummy_instance
10
+ end
11
+
12
+ context('.create_application') do
13
+ it 'should respond to .create_application' do
14
+ expect(@instance).to respond_to :create_application
15
+ end
16
+
17
+ it 'is expected to create a third party application' do
18
+ expect(@instance).to receive(:mgmt_post).with(
19
+ THIRD_PARTY_APP_CREATE_PATH, {
20
+ id: 'app1',
21
+ name: 'test',
22
+ description: 'awesome app',
23
+ logo: 'https://logo.com',
24
+ loginPageUrl: 'https://dummy.com/login',
25
+ approvedCallbackUrls: ['https://dummy.com/callback'],
26
+ permissionsScopes: [{ name: 'read' }],
27
+ attributesScopes: [{ name: 'email' }],
28
+ jwtBearerSettings: [{ tenantId: 'tenant1' }],
29
+ customAttributes: { key: 'value' },
30
+ forcePkce: true,
31
+ defaultAudience: 'aud1'
32
+ }
33
+ )
34
+ expect do
35
+ @instance.create_application(
36
+ id: 'app1',
37
+ name: 'test',
38
+ description: 'awesome app',
39
+ logo: 'https://logo.com',
40
+ login_page_url: 'https://dummy.com/login',
41
+ approved_callback_urls: ['https://dummy.com/callback'],
42
+ permissions_scopes: [{ name: 'read' }],
43
+ attributes_scopes: [{ name: 'email' }],
44
+ jwt_bearer_settings: [{ tenantId: 'tenant1' }],
45
+ custom_attributes: { key: 'value' },
46
+ force_pkce: true,
47
+ default_audience: 'aud1'
48
+ )
49
+ end.not_to raise_error
50
+ end
51
+ end
52
+
53
+ context('.update_application') do
54
+ it 'should respond to .update_application' do
55
+ expect(@instance).to respond_to :update_application
56
+ end
57
+
58
+ it 'is expected to update a third party application' do
59
+ expect(@instance).to receive(:mgmt_post).with(
60
+ THIRD_PARTY_APP_UPDATE_PATH, {
61
+ id: 'app1',
62
+ name: 'test',
63
+ description: 'awesome app',
64
+ logo: 'https://logo.com',
65
+ loginPageUrl: 'https://dummy.com/login'
66
+ }
67
+ )
68
+ expect do
69
+ @instance.update_application(
70
+ id: 'app1',
71
+ name: 'test',
72
+ description: 'awesome app',
73
+ logo: 'https://logo.com',
74
+ login_page_url: 'https://dummy.com/login'
75
+ )
76
+ end.not_to raise_error
77
+ end
78
+ end
79
+
80
+ context('.patch_application') do
81
+ it 'should respond to .patch_application' do
82
+ expect(@instance).to respond_to :patch_application
83
+ end
84
+
85
+ it 'is expected to patch a third party application' do
86
+ expect(@instance).to receive(:mgmt_post).with(
87
+ THIRD_PARTY_APP_PATCH_PATH, {
88
+ id: 'app1',
89
+ name: 'test'
90
+ }
91
+ )
92
+ expect do
93
+ @instance.patch_application(
94
+ id: 'app1',
95
+ name: 'test'
96
+ )
97
+ end.not_to raise_error
98
+ end
99
+ end
100
+
101
+ it 'is expected to delete a third party application' do
102
+ expect(@instance).to receive(:mgmt_post).with(
103
+ THIRD_PARTY_APP_DELETE_PATH, { id: 'app1' }
104
+ )
105
+ expect { @instance.delete_application('app1') }.not_to raise_error
106
+ end
107
+
108
+ it 'is expected to load a third party application' do
109
+ expect(@instance).to receive(:mgmt_get).with(
110
+ THIRD_PARTY_APP_LOAD_PATH, { id: 'app1' }
111
+ )
112
+ expect { @instance.load_application('app1') }.not_to raise_error
113
+ end
114
+
115
+ it 'is expected to load all third party applications' do
116
+ expect(@instance).to receive(:mgmt_get).with(
117
+ THIRD_PARTY_APP_LOAD_ALL_PATH, {}
118
+ )
119
+ expect { @instance.load_all_applications }.not_to raise_error
120
+ end
121
+
122
+ it 'is expected to get a third party application secret' do
123
+ expect(@instance).to receive(:mgmt_get).with(
124
+ THIRD_PARTY_APP_SECRET_PATH, { id: 'app1' }
125
+ )
126
+ expect { @instance.get_application_secret('app1') }.not_to raise_error
127
+ end
128
+
129
+ it 'is expected to rotate a third party application secret' do
130
+ expect(@instance).to receive(:mgmt_post).with(
131
+ THIRD_PARTY_APP_ROTATE_PATH, { id: 'app1' }
132
+ )
133
+ expect { @instance.rotate_application_secret('app1') }.not_to raise_error
134
+ end
135
+
136
+ it 'is expected to delete consents' do
137
+ expect(@instance).to receive(:mgmt_post).with(
138
+ THIRD_PARTY_APP_DELETE_CONSENTS_PATH, {
139
+ consentIds: %w[consent1 consent2],
140
+ appId: 'app1',
141
+ userIds: %w[user1 user2],
142
+ tenantId: 'tenant1'
143
+ }
144
+ )
145
+ expect do
146
+ @instance.delete_consents(
147
+ app_id: 'app1',
148
+ consent_ids: %w[consent1 consent2],
149
+ user_ids: %w[user1 user2],
150
+ tenant_id: 'tenant1'
151
+ )
152
+ end.not_to raise_error
153
+ end
154
+
155
+ it 'is expected to delete tenant consents' do
156
+ expect(@instance).to receive(:mgmt_post).with(
157
+ THIRD_PARTY_APP_DELETE_TENANT_CONSENTS_PATH, {
158
+ consentIds: %w[consent1 consent2],
159
+ appId: 'app1',
160
+ tenantId: 'tenant1'
161
+ }
162
+ )
163
+ expect do
164
+ @instance.delete_tenant_consents(
165
+ app_id: 'app1',
166
+ consent_ids: %w[consent1 consent2],
167
+ tenant_id: 'tenant1'
168
+ )
169
+ end.not_to raise_error
170
+ end
171
+ end
@@ -58,7 +58,7 @@ describe Descope::Api::V1::Management::User do
58
58
  }
59
59
 
60
60
  it 'is expected to create a user with user data' do
61
- expect(@instance).to receive(:post).with(USER_CREATE_PATH, params)
61
+ expect(@instance).to receive(:mgmt_post).with(USER_CREATE_PATH, params)
62
62
 
63
63
  expect do
64
64
  @instance.create_user(**args)
@@ -67,7 +67,7 @@ describe Descope::Api::V1::Management::User do
67
67
 
68
68
  it 'is expected to create a test user with user data' do
69
69
  params[:test] = true
70
- expect(@instance).to receive(:post).with(TEST_USER_CREATE_PATH, params)
70
+ expect(@instance).to receive(:mgmt_post).with(TEST_USER_CREATE_PATH, params)
71
71
 
72
72
  expect do
73
73
  args[:test] = true
@@ -101,7 +101,7 @@ describe Descope::Api::V1::Management::User do
101
101
  }
102
102
  ]
103
103
  }
104
- expect(@instance).to receive(:post).with(
104
+ expect(@instance).to receive(:mgmt_post).with(
105
105
  USER_CREATE_BATCH_PATH, users_params
106
106
  )
107
107
 
@@ -117,7 +117,7 @@ describe Descope::Api::V1::Management::User do
117
117
  end
118
118
 
119
119
  it "is expected to post #{USER_CREATE_PATH} with invite true" do
120
- expect(@instance).to receive(:post).with(
120
+ expect(@instance).to receive(:mgmt_post).with(
121
121
  USER_CREATE_PATH, {
122
122
  loginId: 'name@mail.com',
123
123
  email: 'name@mail.com',
@@ -143,7 +143,7 @@ describe Descope::Api::V1::Management::User do
143
143
  end
144
144
 
145
145
  it 'is expected to respond to a user update method' do
146
- expect(@instance).to receive(:post).with(
146
+ expect(@instance).to receive(:mgmt_post).with(
147
147
  USER_UPDATE_PATH, {
148
148
  loginId: 'name@mail.com',
149
149
  email: 'name@mail.com',
@@ -171,7 +171,7 @@ describe Descope::Api::V1::Management::User do
171
171
  end
172
172
 
173
173
  it 'is expected to respond to a user delete method' do
174
- expect(@instance).to receive(:post).with(
174
+ expect(@instance).to receive(:mgmt_post).with(
175
175
  USER_DELETE_PATH, { loginId: 'name@mail.com' }
176
176
  )
177
177
 
@@ -183,7 +183,7 @@ describe Descope::Api::V1::Management::User do
183
183
 
184
184
  context '.delete_all_user' do
185
185
  it 'is expected to respond to a user delete method' do
186
- expect(@instance).to receive(:delete).with(USER_DELETE_ALL_TEST_USERS_PATH)
186
+ expect(@instance).to receive(:mgmt_delete).with(USER_DELETE_ALL_TEST_USERS_PATH)
187
187
 
188
188
  expect do
189
189
  @instance.delete_all_test_users
@@ -197,7 +197,7 @@ describe Descope::Api::V1::Management::User do
197
197
  end
198
198
 
199
199
  it "is expected to get #{USER_LOAD_PATH} with login_id" do
200
- expect(@instance).to receive(:get).with(
200
+ expect(@instance).to receive(:mgmt_get).with(
201
201
  USER_LOAD_PATH, { loginId: 'someone' }
202
202
  )
203
203
  expect { @instance.load_user('someone') }.not_to raise_error
@@ -206,7 +206,7 @@ describe Descope::Api::V1::Management::User do
206
206
 
207
207
  context '.load_by_user_id' do
208
208
  it "is expected to get #{USER_LOAD_PATH} with user_id" do
209
- allow(@instance).to receive(:get).with(
209
+ allow(@instance).to receive(:mgmt_get).with(
210
210
  USER_LOAD_PATH, { userId: 'ABCD' }
211
211
  )
212
212
  expect { @instance.load_by_user_id('ABCD') }.not_to raise_error
@@ -215,7 +215,7 @@ describe Descope::Api::V1::Management::User do
215
215
 
216
216
  context '.logout_user' do
217
217
  it 'is expected to respond to a logout user method' do
218
- expect(@instance).to receive(:post).with(
218
+ expect(@instance).to receive(:mgmt_post).with(
219
219
  USER_LOGOUT_PATH, { loginId: 'name@mail.com' }
220
220
  )
221
221
 
@@ -225,7 +225,7 @@ describe Descope::Api::V1::Management::User do
225
225
  end
226
226
 
227
227
  it 'is expected to respond to a logout user by id method' do
228
- expect(@instance).to receive(:post).with(
228
+ expect(@instance).to receive(:mgmt_post).with(
229
229
  USER_LOGOUT_PATH, { userId: 'U2ZpARjKAJJmq0fzU2lXNNCGnF4j' }
230
230
  )
231
231
 
@@ -241,7 +241,7 @@ describe Descope::Api::V1::Management::User do
241
241
 
242
242
  tenant_role_ids = { 'tenant1' => ['roleA', 'roleB'] }
243
243
  tenant_role_names = { 'tenant1' => ['roleName1', 'roleName2'] }
244
- expect(@instance).to receive(:post).with(
244
+ expect(@instance).to receive(:mgmt_post).with(
245
245
  USERS_SEARCH_PATH, {
246
246
  loginId: 'someone@example.com',
247
247
  tenantIds: [],
@@ -284,7 +284,7 @@ describe Descope::Api::V1::Management::User do
284
284
  it 'is expected to respond to a get_provider_token method' do
285
285
  expect(@instance).to respond_to(:get_provider_token)
286
286
 
287
- expect(@instance).to receive(:get).with(
287
+ expect(@instance).to receive(:mgmt_get).with(
288
288
  USER_GET_PROVIDER_TOKEN, {
289
289
  loginId: 'someone@example.com',
290
290
  provider: 'google-oauth2'
@@ -304,7 +304,7 @@ describe Descope::Api::V1::Management::User do
304
304
  it 'is expected to respond to a activate method' do
305
305
  expect(@instance).to respond_to(:activate)
306
306
 
307
- expect(@instance).to receive(:post).with(
307
+ expect(@instance).to receive(:mgmt_post).with(
308
308
  USER_UPDATE_STATUS_PATH, {
309
309
  loginId: 'someone@example.com',
310
310
  status: 'enabled'
@@ -321,7 +321,7 @@ describe Descope::Api::V1::Management::User do
321
321
  it 'is expected to respond to a activate method' do
322
322
  expect(@instance).to respond_to(:activate)
323
323
 
324
- expect(@instance).to receive(:post).with(
324
+ expect(@instance).to receive(:mgmt_post).with(
325
325
  USER_UPDATE_STATUS_PATH, {
326
326
  loginId: 'someone@example.com',
327
327
  status: 'disabled'
@@ -338,7 +338,7 @@ describe Descope::Api::V1::Management::User do
338
338
  it 'is expected to respond to a update_email method' do
339
339
  expect(@instance).to respond_to(:update_email)
340
340
 
341
- expect(@instance).to receive(:post).with(
341
+ expect(@instance).to receive(:mgmt_post).with(
342
342
  USER_UPDATE_EMAIL_PATH, {
343
343
  loginId: 'someone@example.com',
344
344
  email: 'tester@test.com',
@@ -360,7 +360,7 @@ describe Descope::Api::V1::Management::User do
360
360
  it 'is expected to respond to a update_phone method' do
361
361
  expect(@instance).to respond_to(:update_phone)
362
362
 
363
- expect(@instance).to receive(:post).with(
363
+ expect(@instance).to receive(:mgmt_post).with(
364
364
  USER_UPDATE_PHONE_PATH, {
365
365
  loginId: 'someone@example.com',
366
366
  phone: '1234567890',
@@ -382,7 +382,7 @@ describe Descope::Api::V1::Management::User do
382
382
  it 'is expected to respond to a update_display_name method' do
383
383
  expect(@instance).to respond_to(:update_display_name)
384
384
 
385
- expect(@instance).to receive(:post).with(
385
+ expect(@instance).to receive(:mgmt_post).with(
386
386
  USER_UPDATE_NAME_PATH, {
387
387
  loginId: 'someone@example.com',
388
388
  name: 'some guy',
@@ -408,7 +408,7 @@ describe Descope::Api::V1::Management::User do
408
408
  it 'is expected to respond to a update_picture method' do
409
409
  expect(@instance).to respond_to(:update_picture)
410
410
 
411
- expect(@instance).to receive(:post).with(
411
+ expect(@instance).to receive(:mgmt_post).with(
412
412
  USER_UPDATE_PICTURE_PATH, {
413
413
  loginId: 'someone@example.com',
414
414
  picture: 'https://www.example.com/picture.png'
@@ -428,7 +428,7 @@ describe Descope::Api::V1::Management::User do
428
428
  it 'is expected to respond to a update_custom_attribute method' do
429
429
  expect(@instance).to respond_to(:update_custom_attribute)
430
430
 
431
- expect(@instance).to receive(:post).with(
431
+ expect(@instance).to receive(:mgmt_post).with(
432
432
  USER_UPDATE_CUSTOM_ATTRIBUTE_PATH, {
433
433
  loginId: 'someone@example.com',
434
434
  attributeKey: 'OU',
@@ -450,7 +450,7 @@ describe Descope::Api::V1::Management::User do
450
450
  it 'is expected to respond to a add_roles method' do
451
451
  expect(@instance).to respond_to(:user_add_roles)
452
452
 
453
- expect(@instance).to receive(:post).with(
453
+ expect(@instance).to receive(:mgmt_post).with(
454
454
  USER_ADD_ROLE_PATH, {
455
455
  loginId: 'someone@example.com',
456
456
  roleNames: %w[role1 role2],
@@ -472,7 +472,7 @@ describe Descope::Api::V1::Management::User do
472
472
  it 'is expected to respond to a user_remove_roles method' do
473
473
  expect(@instance).to respond_to(:user_remove_roles)
474
474
 
475
- expect(@instance).to receive(:post).with(
475
+ expect(@instance).to receive(:mgmt_post).with(
476
476
  USER_REMOVE_ROLE_PATH, {
477
477
  loginId: 'someone@example.com',
478
478
  roleNames: %w[role1 role2],
@@ -494,7 +494,7 @@ describe Descope::Api::V1::Management::User do
494
494
  it 'is expected to respond to a add_tenant method' do
495
495
  expect(@instance).to respond_to(:user_add_tenant)
496
496
 
497
- expect(@instance).to receive(:post).with(
497
+ expect(@instance).to receive(:mgmt_post).with(
498
498
  USER_ADD_TENANT_PATH, {
499
499
  loginId: 'someone@example.com',
500
500
  tenantId: 'tenant1'
@@ -514,7 +514,7 @@ describe Descope::Api::V1::Management::User do
514
514
  it 'is expected to respond to a remove_tenant method' do
515
515
  expect(@instance).to respond_to(:user_remove_tenant)
516
516
 
517
- expect(@instance).to receive(:post).with(
517
+ expect(@instance).to receive(:mgmt_post).with(
518
518
  USER_REMOVE_TENANT_PATH, {
519
519
  loginId: 'someone@example.com',
520
520
  tenantId: 'tenant1'
@@ -534,7 +534,7 @@ describe Descope::Api::V1::Management::User do
534
534
  it 'is expected to respond to a add_tenant_role method' do
535
535
  expect(@instance).to respond_to(:add_tenant_role)
536
536
 
537
- expect(@instance).to receive(:post).with(
537
+ expect(@instance).to receive(:mgmt_post).with(
538
538
  USER_ADD_TENANT_PATH, {
539
539
  loginId: 'someone@example.com',
540
540
  tenantId: 'tenant1',
@@ -556,7 +556,7 @@ describe Descope::Api::V1::Management::User do
556
556
  it 'is expected to respond to a remove_tenant_role method' do
557
557
  expect(@instance).to respond_to(:user_remove_tenant_roles)
558
558
 
559
- expect(@instance).to receive(:post).with(
559
+ expect(@instance).to receive(:mgmt_post).with(
560
560
  USER_REMOVE_TENANT_PATH, {
561
561
  loginId: 'someone@example.com',
562
562
  tenantId: 'tenant1',
@@ -578,7 +578,7 @@ describe Descope::Api::V1::Management::User do
578
578
  it 'is expected to respond to a set_temporary_password method' do
579
579
  expect(@instance).to respond_to(:set_temporary_password)
580
580
 
581
- expect(@instance).to receive(:post).with(
581
+ expect(@instance).to receive(:mgmt_post).with(
582
582
  USER_SET_TEMPORARY_PASSWORD_PATH, {
583
583
  loginId: 'someone@example.com',
584
584
  password: 's3cr3t'
@@ -598,7 +598,7 @@ describe Descope::Api::V1::Management::User do
598
598
  it 'is expected to respond to a set_active_password method' do
599
599
  expect(@instance).to respond_to(:set_active_password)
600
600
 
601
- expect(@instance).to receive(:post).with(
601
+ expect(@instance).to receive(:mgmt_post).with(
602
602
  USER_SET_ACTIVE_PASSWORD_PATH, {
603
603
  loginId: 'someone@example.com',
604
604
  password: 's3cr3t'
@@ -618,7 +618,7 @@ describe Descope::Api::V1::Management::User do
618
618
  it 'is expected to respond to a set_password method' do
619
619
  expect(@instance).to respond_to(:set_password)
620
620
 
621
- expect(@instance).to receive(:post).with(
621
+ expect(@instance).to receive(:mgmt_post).with(
622
622
  USER_SET_PASSWORD_PATH, {
623
623
  loginId: 'someone@example.com',
624
624
  password: 's3cr3t'
@@ -638,7 +638,7 @@ describe Descope::Api::V1::Management::User do
638
638
  it 'is expected to respond to a expire_password method' do
639
639
  expect(@instance).to respond_to(:expire_password)
640
640
 
641
- expect(@instance).to receive(:post).with(
641
+ expect(@instance).to receive(:mgmt_post).with(
642
642
  USER_EXPIRE_PASSWORD_PATH, { loginId: 'someone@example.com' }
643
643
  )
644
644
 
@@ -650,7 +650,7 @@ describe Descope::Api::V1::Management::User do
650
650
  it 'is expected to respond to a generate_otp_for_test method' do
651
651
  expect(@instance).to respond_to(:generate_otp_for_test_user)
652
652
 
653
- expect(@instance).to receive(:post).with(
653
+ expect(@instance).to receive(:mgmt_post).with(
654
654
  USER_GENERATE_OTP_FOR_TEST_PATH, {
655
655
  loginId: 'someone@example.com',
656
656
  deliveryMethod: 'email'
@@ -670,7 +670,7 @@ describe Descope::Api::V1::Management::User do
670
670
  it 'is expected to respond to a generate_enchanted_link_for_test method' do
671
671
  expect(@instance).to respond_to(:generate_enchanted_link_for_test_user)
672
672
 
673
- expect(@instance).to receive(:post).with(
673
+ expect(@instance).to receive(:mgmt_post).with(
674
674
  USER_GENERATE_ENCHANTED_LINK_FOR_TEST_PATH, {
675
675
  loginId: 'someone@example.com',
676
676
  URI: 'https://www.example.com'
@@ -690,7 +690,7 @@ describe Descope::Api::V1::Management::User do
690
690
  it 'is expected to respond to a update_jwt method' do
691
691
  expect(@instance).to respond_to(:update_jwt)
692
692
 
693
- expect(@instance).to receive(:post).with(
693
+ expect(@instance).to receive(:mgmt_post).with(
694
694
  UPDATE_JWT_PATH, {
695
695
  jwt: 'eyJ3abcde12345',
696
696
  customClaims: { 'claim1' => 'value1', 'claim2' => 'value2' }
@@ -717,7 +717,7 @@ describe Descope::Api::V1::Management::User do
717
717
  customClaims: { 'abc': '123' }
718
718
  }
719
719
 
720
- expect(@instance).to receive(:post).with(
720
+ expect(@instance).to receive(:mgmt_post).with(
721
721
  USER_GENERATE_EMBEDDED_LINK_PATH,
722
722
  request_params
723
723
  )
@@ -737,7 +737,7 @@ describe Descope::Api::V1::Management::User do
737
737
  end
738
738
 
739
739
  it 'is expected to respond to a user patch method' do
740
- expect(@instance).to receive(:patch).with(
740
+ expect(@instance).to receive(:mgmt_patch).with(
741
741
  USER_PATCH_PATH, {
742
742
  loginId: 'name@mail.com',
743
743
  email: 'name@mail.com',
@@ -765,7 +765,7 @@ describe Descope::Api::V1::Management::User do
765
765
 
766
766
  tenant_role_ids = { 'tenant1' => ['roleA', 'roleB'] }
767
767
  tenant_role_names = { 'tenant1' => ['roleName1', 'roleName2'] }
768
- expect(@instance).to receive(:post).with(
768
+ expect(@instance).to receive(:mgmt_post).with(
769
769
  TEST_USERS_SEARCH_PATH, {
770
770
  tenantIds: %w[t1 t2],
771
771
  roleNames: %w[r1 r2],
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # Covers the Authorization header the SDK actually sends. The auth management key rides along with
6
+ # every authentication request so that methods whose public access has been disabled can still be
7
+ # used, and it is never sent on management requests - those carry the management key instead.
8
+ describe 'auth management key' do
9
+ let(:project_id) { 'P2abcde12345' }
10
+ let(:management_key) { 'mgmt-key' }
11
+ let(:auth_management_key) { 'auth-key' }
12
+ let(:refresh_token) { 'refresh-token' }
13
+
14
+ # Stubs the RestClient boundary on both of the client's HTTP clients and hands back the
15
+ # Authorization header of whichever one ends up being used.
16
+ def authorization_for(client)
17
+ captured = nil
18
+ [client.auth_http, client.mgmt_http].each do |http|
19
+ allow(http).to receive(:call) do |_method, _url, _timeout, headers, _body|
20
+ captured = headers['Authorization']
21
+ double('response', code: 200, body: '{}', cookies: {}, headers: {})
22
+ end
23
+ end
24
+ yield
25
+ captured
26
+ end
27
+
28
+ def build_client(**options)
29
+ Descope::Client.new({ project_id: project_id, log_level: 'fatal' }.merge(options))
30
+ end
31
+
32
+ # An authentication request that presents no token of its own.
33
+ def sign_up(client)
34
+ client.otp_sign_up(method: Descope::Mixins::Common::DeliveryMethod::EMAIL, login_id: 'someone@example.com')
35
+ end
36
+
37
+ around do |example|
38
+ keys = %w[DESCOPE_MANAGEMENT_KEY DESCOPE_AUTH_MANAGEMENT_KEY]
39
+ saved = keys.to_h { |var| [var, ENV[var]] }
40
+ keys.each { |var| ENV.delete(var) }
41
+ example.run
42
+ ensure
43
+ saved.each { |var, value| ENV[var] = value }
44
+ end
45
+
46
+ context 'on authentication requests' do
47
+ it 'sends only the project ID when no auth management key is configured' do
48
+ client = build_client
49
+ header = authorization_for(client) { sign_up(client) }
50
+ expect(header).to eq("Bearer #{project_id}")
51
+ end
52
+
53
+ it 'appends the auth management key when one is configured' do
54
+ client = build_client(auth_management_key: auth_management_key)
55
+ header = authorization_for(client) { sign_up(client) }
56
+ expect(header).to eq("Bearer #{project_id}:#{auth_management_key}")
57
+ end
58
+
59
+ it 'appends the auth management key after a refresh token' do
60
+ client = build_client(auth_management_key: auth_management_key)
61
+ header = authorization_for(client) { client.me(refresh_token) }
62
+ expect(header).to eq("Bearer #{project_id}:#{refresh_token}:#{auth_management_key}")
63
+ end
64
+
65
+ it 'never sends the management key' do
66
+ client = build_client(management_key: management_key, auth_management_key: auth_management_key)
67
+ header = authorization_for(client) { sign_up(client) }
68
+ expect(header).to eq("Bearer #{project_id}:#{auth_management_key}")
69
+ expect(header).to_not include(management_key)
70
+ end
71
+
72
+ # DummyClass swallows extra_headers, so only a real client exercises this argument.
73
+ it 'tolerates a nil extra_headers from the caller' do
74
+ client = build_client(auth_management_key: auth_management_key)
75
+ header = authorization_for(client) { client.post(SIGN_IN_PASSWORD_PATH, {}, nil, refresh_token) }
76
+ expect(header).to eq("Bearer #{project_id}:#{refresh_token}:#{auth_management_key}")
77
+ end
78
+
79
+ it 'signs in with an enchanted link' do
80
+ client = build_client(auth_management_key: auth_management_key)
81
+ header = authorization_for(client) do
82
+ client.enchanted_link_sign_in(login_id: 'someone@example.com', uri: 'https://example.com')
83
+ end
84
+ expect(header).to eq("Bearer #{project_id}:#{auth_management_key}")
85
+ end
86
+
87
+ it 'does not substitute a key for an empty refresh token' do
88
+ client = build_client(management_key: management_key, auth_management_key: auth_management_key)
89
+ header = authorization_for(client) { client.sign_out('') }
90
+ expect(header).to eq("Bearer #{project_id}:#{auth_management_key}")
91
+ end
92
+ end
93
+
94
+ context 'on management requests' do
95
+ it 'appends the management key' do
96
+ client = build_client(management_key: management_key)
97
+ header = authorization_for(client) { client.load_all_tenants }
98
+ expect(header).to eq("Bearer #{project_id}:#{management_key}")
99
+ end
100
+
101
+ it 'never sends the auth management key' do
102
+ client = build_client(management_key: management_key, auth_management_key: auth_management_key)
103
+ header = authorization_for(client) { client.load_all_tenants }
104
+ expect(header).to eq("Bearer #{project_id}:#{management_key}")
105
+ expect(header).to_not include(auth_management_key)
106
+ end
107
+
108
+ it 'sends only the project ID when no management key is configured' do
109
+ client = build_client(auth_management_key: auth_management_key)
110
+ header = authorization_for(client) { client.load_all_tenants }
111
+ expect(header).to eq("Bearer #{project_id}")
112
+ end
113
+ end
114
+
115
+ context 'configuration' do
116
+ it 'falls back to the DESCOPE_AUTH_MANAGEMENT_KEY env var' do
117
+ ENV['DESCOPE_AUTH_MANAGEMENT_KEY'] = 'env-auth-key'
118
+ client = build_client
119
+ header = authorization_for(client) { sign_up(client) }
120
+ expect(header).to eq("Bearer #{project_id}:env-auth-key")
121
+ end
122
+
123
+ it 'prefers the configured key over the env var' do
124
+ ENV['DESCOPE_AUTH_MANAGEMENT_KEY'] = 'env-auth-key'
125
+ client = build_client(auth_management_key: auth_management_key)
126
+ header = authorization_for(client) { sign_up(client) }
127
+ expect(header).to eq("Bearer #{project_id}:#{auth_management_key}")
128
+ end
129
+
130
+ it 'keeps the two keys distinct' do
131
+ ENV['DESCOPE_MANAGEMENT_KEY'] = management_key
132
+ ENV['DESCOPE_AUTH_MANAGEMENT_KEY'] = auth_management_key
133
+ client = build_client
134
+ expect(client.auth_http.authorization_header).to eq(
135
+ { 'Authorization' => "Bearer #{project_id}:#{auth_management_key}" }
136
+ )
137
+ expect(client.mgmt_http.authorization_header).to eq(
138
+ { 'Authorization' => "Bearer #{project_id}:#{management_key}" }
139
+ )
140
+ end
141
+ end
142
+
143
+ describe 'debug logging' do
144
+ it 'masks everything after the project ID' do
145
+ client = build_client(auth_management_key: auth_management_key)
146
+ masked = client.auth_http.mask_authorization(client.auth_http.authorization_header)
147
+ expect(masked['Authorization']).to eq("Bearer #{project_id}:***")
148
+ expect(masked['Authorization']).to_not include(auth_management_key)
149
+ end
150
+ end
151
+ end