descope 1.0.5 → 1.0.7

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +2 -2
  3. data/.github/workflows/publish-gem.yaml +39 -7
  4. data/.gitignore +2 -0
  5. data/.ruby-version +1 -1
  6. data/Gemfile +7 -7
  7. data/Gemfile.lock +70 -65
  8. data/README.md +175 -52
  9. data/descope.gemspec +25 -20
  10. data/examples/ruby/.ruby-version +1 -0
  11. data/examples/ruby/access_key_app.rb +4 -3
  12. data/examples/ruby/enchantedlink_app.rb +1 -0
  13. data/examples/ruby/magiclink_app.rb +1 -0
  14. data/examples/ruby/management/.ruby-version +1 -0
  15. data/examples/ruby/management/Gemfile +2 -2
  16. data/examples/ruby/management/access_key_app.rb +2 -0
  17. data/examples/ruby/management/audit_app.rb +32 -8
  18. data/examples/ruby/management/authz_app.rb +1 -0
  19. data/examples/ruby/management/flow_app.rb +1 -0
  20. data/examples/ruby/management/permission_app.rb +3 -2
  21. data/examples/ruby/management/role_app.rb +3 -2
  22. data/examples/ruby/management/tenant_app.rb +1 -0
  23. data/examples/ruby/management/user_app.rb +1 -0
  24. data/examples/ruby/oauth_app.rb +1 -0
  25. data/examples/ruby/otp_app.rb +38 -12
  26. data/examples/ruby/password_app.rb +8 -7
  27. data/examples/ruby/saml_app.rb +1 -0
  28. data/examples/ruby/version_check.rb +17 -0
  29. data/examples/ruby-on-rails-api/descope/Gemfile +9 -7
  30. data/examples/ruby-on-rails-api/descope/Gemfile.lock +121 -90
  31. data/examples/ruby-on-rails-api/descope/README.md +18 -18
  32. data/examples/ruby-on-rails-api/descope/app/assets/builds/application.css +20092 -23
  33. data/examples/ruby-on-rails-api/descope/app/assets/builds/application.js +0 -1
  34. data/examples/ruby-on-rails-api/descope/app/assets/builds/components/index.js +0 -14
  35. data/examples/ruby-on-rails-api/descope/package-lock.json +1073 -19302
  36. data/examples/ruby-on-rails-api/descope/package.json +8 -16
  37. data/examples/ruby-on-rails-api/descope/yarn.lock +557 -10641
  38. data/lib/descope/api/v1/auth/enchantedlink.rb +3 -1
  39. data/lib/descope/api/v1/auth/magiclink.rb +3 -1
  40. data/lib/descope/api/v1/auth/otp.rb +24 -15
  41. data/lib/descope/api/v1/auth/password.rb +6 -2
  42. data/lib/descope/api/v1/auth/totp.rb +3 -1
  43. data/lib/descope/api/v1/auth.rb +64 -32
  44. data/lib/descope/api/v1/management/audit.rb +24 -0
  45. data/lib/descope/api/v1/management/common.rb +21 -5
  46. data/lib/descope/api/v1/management/sso_application.rb +236 -0
  47. data/lib/descope/api/v1/management/sso_settings.rb +2 -24
  48. data/lib/descope/api/v1/management/user.rb +151 -13
  49. data/lib/descope/api/v1/management.rb +2 -0
  50. data/lib/descope/api/v1/session.rb +37 -4
  51. data/lib/descope/mixins/common.rb +6 -2
  52. data/lib/descope/mixins/http.rb +60 -9
  53. data/lib/descope/mixins/initializer.rb +2 -1
  54. data/lib/descope/mixins/logging.rb +12 -4
  55. data/lib/descope/mixins/validation.rb +21 -6
  56. data/lib/descope/version.rb +1 -1
  57. data/spec/descope/api/v1/auth_spec.rb +29 -0
  58. data/spec/descope/api/v1/auth_token_extraction_spec.rb +126 -0
  59. data/spec/descope/api/v1/session_refresh_spec.rb +98 -0
  60. data/spec/factories/user.rb +1 -1
  61. data/spec/integration/lib.descope/api/v1/auth/enchantedlink_spec.rb +1 -1
  62. data/spec/integration/lib.descope/api/v1/auth/magiclink_spec.rb +1 -1
  63. data/spec/integration/lib.descope/api/v1/auth/otp_spec.rb +73 -8
  64. data/spec/integration/lib.descope/api/v1/auth/session_spec.rb +49 -0
  65. data/spec/integration/lib.descope/api/v1/auth/totp_spec.rb +1 -1
  66. data/spec/integration/lib.descope/api/v1/management/access_key_spec.rb +3 -0
  67. data/spec/integration/lib.descope/api/v1/management/audit_spec.rb +38 -0
  68. data/spec/integration/lib.descope/api/v1/management/authz_spec.rb +2 -0
  69. data/spec/integration/lib.descope/api/v1/management/flow_spec.rb +3 -1
  70. data/spec/integration/lib.descope/api/v1/management/permissions_spec.rb +4 -2
  71. data/spec/integration/lib.descope/api/v1/management/project_spec.rb +2 -0
  72. data/spec/integration/lib.descope/api/v1/management/roles_spec.rb +3 -1
  73. data/spec/integration/lib.descope/api/v1/management/user_spec.rb +55 -6
  74. data/spec/lib.descope/api/v1/auth/enchantedlink_spec.rb +11 -2
  75. data/spec/lib.descope/api/v1/auth/otp_spec.rb +176 -18
  76. data/spec/lib.descope/api/v1/auth/password_spec.rb +10 -1
  77. data/spec/lib.descope/api/v1/auth_spec.rb +168 -6
  78. data/spec/lib.descope/api/v1/cookie_domain_fix_integration_spec.rb +245 -0
  79. data/spec/lib.descope/api/v1/management/audit_spec.rb +92 -0
  80. data/spec/lib.descope/api/v1/management/sso_application_spec.rb +217 -0
  81. data/spec/lib.descope/api/v1/management/sso_settings_spec.rb +2 -2
  82. data/spec/lib.descope/api/v1/management/user_spec.rb +134 -46
  83. data/spec/lib.descope/api/v1/session_spec.rb +119 -6
  84. data/spec/lib.descope/mixins/http_spec.rb +218 -0
  85. data/spec/support/client_config.rb +0 -1
  86. data/spec/support/utils.rb +6 -0
  87. metadata +34 -137
  88. data/examples/ruby-on-rails-api/descope/app/assets/builds/reportWebVitals.js +0 -211
  89. data/examples/ruby-on-rails-api/descope/app/assets/builds/reportWebVitals.js.map +0 -7
@@ -12,7 +12,7 @@ describe Descope::Api::V1::Auth::TOTP do
12
12
  @client.logger.info('Cleaning up test users...')
13
13
  all_users = @client.search_all_users
14
14
  all_users['users'].each do |user|
15
- if user['middleName'] == 'Ruby SDK User'
15
+ if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
16
16
  @client.logger.info("Deleting ruby spec test user #{user['loginIds'][0]}")
17
17
  @client.delete_user(user['loginIds'][0])
18
18
  end
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::AccessKey do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  end
9
11
 
@@ -28,6 +30,7 @@ describe Descope::Api::V1::Management::AccessKey do
28
30
  @tenant_id = @client.create_tenant(name: 'some-new-tenant')['id']
29
31
  @client.logger.info('creating access key')
30
32
  @access_key = @client.create_access_key(name: @key_name, key_tenants: [{ tenant_id: @tenant_id }])
33
+ @client.logger.info("waiting for access key #{@access_key['key']['id']} to be active 60 seconds")
31
34
  sleep 60
32
35
  end
33
36
 
@@ -4,13 +4,51 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Audit do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
10
+ @client.logger.info('Deleting all tenants for Ruby SDK...')
11
+ @client.search_all_tenants(names: ['Ruby-SDK-test'])['tenants'].each do |tenant|
12
+ @client.logger.info("Deleting tenant: #{tenant['name']}")
13
+ @client.delete_tenant(tenant['id'])
14
+ end
15
+ @client.logger.info('Cleanup completed. Starting tests...')
8
16
  end
9
17
 
18
+ after(:all) do
19
+ all_users = @client.search_all_users
20
+ all_users['users'].each do |user|
21
+ if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
22
+ puts "Deleting ruby spec test user #{user['loginIds'][0]}"
23
+ @client.delete_user(user['loginIds'][0])
24
+ end
25
+ end
26
+ end
10
27
 
11
28
  it 'should search the audit trail for user operations' do
12
29
  res = @client.audit_search(actions: ['LoginSucceed'])
13
30
  expect(res).to be_a(Hash)
14
31
  expect(res['audits']).to be_a(Array)
15
32
  end
33
+
34
+ it 'should create a new audit event' do
35
+ # Create tenants
36
+ @client.logger.info('creating Ruby-SDK-test tenant')
37
+ tenant_id = @client.create_tenant(name: 'Ruby-SDK-test')['id']
38
+
39
+ # Create a user (actor)
40
+ user = build(:user)
41
+ created_user = @client.create_user(**user)['user']
42
+
43
+ expect do
44
+ @client.audit_create_event(
45
+ user_id: created_user['loginId'],
46
+ action: 'pencil.created',
47
+ type: 'info',
48
+ tenant_id:,
49
+ actor_id: created_user['loginIds'][0],
50
+ data: { 'key' => 'value' }
51
+ )
52
+ end.not_to raise_error
53
+ end
16
54
  end
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Authz do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  puts 'authz schema delete'
9
11
  end
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Flow do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  end
9
11
 
@@ -38,7 +40,7 @@ describe Descope::Api::V1::Management::Flow do
38
40
  it 'should import the current project theme' do
39
41
  export_theme = @client.export_theme
40
42
  export_theme_current_version = export_theme['theme']['version']
41
- imported_theme = @client.import_theme(export_theme)
43
+ imported_theme = @client.import_theme(export_theme['theme'])
42
44
  expect(imported_theme['theme']['version']).to be(export_theme_current_version + 1)
43
45
  end
44
46
  end
@@ -4,9 +4,11 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Permission do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  @client.load_all_permissions['permissions'].each do |perm|
9
- if perm['description'] == 'Ruby SDK'
11
+ if perm['description'] == "#{SpecUtils.build_prefix} Ruby SDK"
10
12
  puts "Deleting permission: #{perm['name']}"
11
13
  @client.delete_permission(perm['name'])
12
14
  end
@@ -14,7 +16,7 @@ describe Descope::Api::V1::Management::Permission do
14
16
  end
15
17
 
16
18
  it 'should create update and delete a permission' do
17
- @client.create_permission(name: 'test_permission', description: 'Ruby SDK')
19
+ @client.create_permission(name: 'test_permission', description: "#{SpecUtils.build_prefix} Ruby SDK")
18
20
  all_permissions = @client.load_all_permissions['permissions']
19
21
  expect(all_permissions.any? { |perm| perm['name'] == 'test_permission' }).to eq(true)
20
22
  @client.update_permission(name: 'test_permission', new_name: 'test_permission_2')
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Project do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  @export_output = @client.export_project
9
11
  end
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::Role do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
7
9
  @client = DescopeClient.new(Configuration.config)
8
10
  @client.logger.info('Staring cleanup before tests...')
9
11
  @client.logger.info('Deleting all permissions for Ruby SDK...')
@@ -96,7 +98,7 @@ describe Descope::Api::V1::Management::Role do
96
98
  expect(all_roles.map { |role| role['name'] }).to include('Ruby-SDK-test-admin')
97
99
 
98
100
  @client.logger.info('searching for roles with tenant ids...')
99
- all_roles = @client.search_roles(tenant_ids: %w[Ruby-SDK-test])['roles']
101
+ all_roles = @client.search_roles(role_name_like: 'Ruby-SDK-test', tenant_ids: [tenant_id])['roles']
100
102
  expect(all_roles.map { |role| role['name'] }).to include('Ruby-SDK-test-admin')
101
103
 
102
104
  @client.logger.info('deleting permission')
@@ -4,17 +4,21 @@ require 'spec_helper'
4
4
 
5
5
  describe Descope::Api::V1::Management::User do
6
6
  before(:all) do
7
+ raise 'DESCOPE_MANAGEMENT_KEY is not set' if ENV['DESCOPE_MANAGEMENT_KEY'].nil?
8
+
9
+ @client = DescopeClient.new(Configuration.config)
10
+
7
11
  @password = SpecUtils.generate_password
8
12
  @new_password = SpecUtils.generate_password
9
13
  @user = build(:user)
10
- @client = DescopeClient.new(Configuration.config)
14
+
11
15
  include Descope::Mixins::Common::DeliveryMethod
12
16
  end
13
17
 
14
18
  after(:all) do
15
19
  all_users = @client.search_all_users
16
20
  all_users['users'].each do |user|
17
- if user['middleName'] == 'Ruby SDK User'
21
+ if user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User"
18
22
  puts "Deleting ruby spec test user #{user['loginIds'][0]}"
19
23
  @client.delete_user(user['loginIds'][0])
20
24
  end
@@ -58,6 +62,41 @@ describe Descope::Api::V1::Management::User do
58
62
  expect(updated_user['first_name']).to eq(created_user[updated_first_name])
59
63
  end
60
64
 
65
+ it 'should patch a user' do
66
+ user = build(:user)
67
+ role_name = 'some-new-role'
68
+
69
+ # ensure no roles exist with that name
70
+ all_roles = @client.load_all_roles
71
+ all_roles['roles'].each do |role|
72
+ @client.delete_role(name: role['name']) if role['name'] == role_name
73
+ end
74
+
75
+ @client.create_role(name: role_name)
76
+ @client.create_user(**user)['user']
77
+ updated_first_name = 'new name'
78
+ updated_given_name = 'new given name'
79
+ update_phone_number = "+1#{Faker::Number.number(digits: 10)}"
80
+ updated_role_names = [role_name]
81
+ updated_middle_name = 'new middle name'
82
+ updated_user = @client.patch_user(
83
+ **user,
84
+ name: updated_first_name,
85
+ given_name: updated_given_name,
86
+ phone: update_phone_number,
87
+ role_names: updated_role_names,
88
+ middle_name: updated_middle_name
89
+ )['user']
90
+
91
+ puts "updated_user #{updated_user}"
92
+
93
+ expect(updated_user['name']).to eq(updated_first_name)
94
+ expect(updated_user['givenName']).to eq(updated_given_name)
95
+ expect(updated_user['phone']).to eq(update_phone_number)
96
+ expect(updated_user['roleNames']).to eq(updated_role_names)
97
+ expect(updated_user['middleName']).to eq(updated_middle_name)
98
+ end
99
+
61
100
  it 'should delete a user' do
62
101
  user = build(:user)
63
102
  created_user = @client.create_user(**user)['user']
@@ -77,18 +116,28 @@ describe Descope::Api::V1::Management::User do
77
116
  users = FactoryBot.build_list(:user, 5)
78
117
  @client.create_batch_users(users)
79
118
  all_users = @client.search_all_users
80
- sdk_users = all_users['users'].select { |user| user['middleName'] == 'Ruby SDK User' }
119
+ sdk_users = all_users['users'].select { |user| user['middleName'] == "#{SpecUtils.build_prefix}Ruby-SDK-User" }
81
120
  expect(sdk_users.length).to be >= 5
82
121
  end
83
122
 
84
123
  it 'should create a test user' do
85
124
  @client.delete_all_test_users
125
+ # ensure no roles exist with that name
126
+ role_name = 'some-new-role'
127
+ all_roles = @client.load_all_roles
128
+ all_roles['roles'].each do |role|
129
+ @client.delete_role(name: role['name']) if role['name'] == role_name
130
+ end
86
131
  sleep 5
132
+
87
133
  user_args = build(:user)
88
134
  test_user = @client.create_test_user(**user_args)['user']
89
- test_users = @client.search_all_users(test_users_only: true)['users']
135
+ @client.create_role(name: role_name)
136
+ @client.user_add_roles(login_id: test_user['loginIds'][0], role_names: [role_name])
137
+ test_users = @client.search_all_test_users(role_names: [role_name])['users']
90
138
  expect(test_users.length).to be >= 1
91
139
  expect(test_users[0]['loginIds'][0]).to eq(test_user['loginIds'][0])
140
+ expect(test_users[0]['roleNames']).to eq([role_name])
92
141
  end
93
142
 
94
143
  it 'should update user status' do
@@ -191,8 +240,8 @@ describe Descope::Api::V1::Management::User do
191
240
  new_password = SpecUtils.generate_password
192
241
  @client.set_password(login_id: user['loginIds'][0], password: new_password)
193
242
  @client.password_sign_in(login_id: user['loginIds'][0], password:)
194
- rescue Descope::ServerError => e
195
- expect(e.message).to match(/"errorCode":"E062909"/)
243
+ rescue Descope::Unauthorized => e
244
+ expect(e.message).to match(/"Invalid signin credentials"/)
196
245
  end
197
246
  end
198
247
 
@@ -51,7 +51,7 @@ describe Descope::Api::V1::EnchantedLink do
51
51
 
52
52
  it 'is expected to validate refresh token and not raise an error with refresh token and valid login options' do
53
53
  expect do
54
- @instance.send(:validate_refresh_token_provided, { mfa: true, stepup: true }, 'some-token')
54
+ @instance.send(:validate_refresh_token_provided, { mfa: true, stepup: true }, 'some-token')
55
55
  end.not_to raise_error
56
56
  end
57
57
 
@@ -148,7 +148,16 @@ describe Descope::Api::V1::EnchantedLink do
148
148
  end
149
149
 
150
150
  it 'is expected to get session by pending ref with enchanted link' do
151
- jwt_response = { 'fake': 'response' }
151
+ jwt_response = {
152
+ 'sessionJwt' => 'fake_session_jwt',
153
+ 'refreshJwt' => 'fake_refresh_jwt',
154
+ 'cookies' => {
155
+ 'refresh_token' => 'fake_refresh_cookie'
156
+ }
157
+ }
158
+ allow(@instance).to receive(:post).with(
159
+ GET_SESSION_ENCHANTEDLINK_AUTH_PATH, { pendingRef: 'pendingRef' }
160
+ ).and_return(jwt_response)
152
161
  allow(@instance).to receive(:generate_jwt_response).and_return(jwt_response)
153
162
 
154
163
  expect do
@@ -11,14 +11,15 @@ describe Descope::Api::V1::OTP do
11
11
  @instance = dummy_instance
12
12
  end
13
13
 
14
+ # Sign In methods
14
15
  context '.sign_in' do
15
16
  it 'is expected to respond to sign in using otp' do
16
17
  expect(@instance).to respond_to(:otp_sign_in)
17
18
  end
18
19
 
19
- it 'is expected to sign in with otp' do
20
+ it 'is expected to sign in with otp with email' do
20
21
  request_params = {
21
- loginId: 'test',
22
+ loginId: 'dummy@dummy.com',
22
23
  loginOptions: {
23
24
  stepup: false,
24
25
  customClaims: { 'abc': '123' },
@@ -38,7 +39,7 @@ describe Descope::Api::V1::OTP do
38
39
  expect do
39
40
  @instance.otp_sign_in(
40
41
  method: DeliveryMethod::EMAIL,
41
- login_id: 'test',
42
+ login_id: 'dummy@dummy.com',
42
43
  login_options: {
43
44
  stepup: false,
44
45
  custom_claims: { 'abc': '123' },
@@ -50,15 +51,15 @@ describe Descope::Api::V1::OTP do
50
51
  end.not_to raise_error
51
52
  end
52
53
 
53
- it 'is expected to sign in with otp phone' do
54
+ it 'is expected to sign in with otp phone SMS' do
54
55
  request_params = {
55
- loginId: 'test',
56
+ loginId: '+12122242225',
56
57
  loginOptions: {
57
58
  stepup: false,
58
59
  customClaims: { 'abc': '123' },
59
60
  mfa: false,
60
61
  ssoAppId: 'sso-id'
61
- },
62
+ }
62
63
  }
63
64
  expect(@instance).to receive(:post).with(
64
65
  otp_compose_signin_url(DeliveryMethod::SMS),
@@ -76,7 +77,45 @@ describe Descope::Api::V1::OTP do
76
77
  expect do
77
78
  @instance.otp_sign_in(
78
79
  method: DeliveryMethod::SMS,
79
- login_id: 'test',
80
+ login_id: '+12122242225',
81
+ login_options: {
82
+ stepup: false,
83
+ custom_claims: { 'abc': '123' },
84
+ mfa: false,
85
+ sso_app_id: 'sso-id'
86
+ },
87
+ refresh_token: 'refresh_token'
88
+ )
89
+ end.not_to raise_error
90
+ end
91
+
92
+ it 'is expected to sign in with otp Voice' do
93
+ request_params = {
94
+ loginId: '+12122242225',
95
+ loginOptions: {
96
+ stepup: false,
97
+ customClaims: { 'abc': '123' },
98
+ mfa: false,
99
+ ssoAppId: 'sso-id'
100
+ }
101
+ }
102
+ expect(@instance).to receive(:post).with(
103
+ otp_compose_signin_url(DeliveryMethod::VOICE),
104
+ request_params,
105
+ {},
106
+ 'refresh_token'
107
+ )
108
+
109
+ allow_any_instance_of(Descope::Api::V1::Auth::OTP).to receive(:extract_masked_address).and_return(
110
+ {
111
+ 'maskedPhone' => '+1******890'
112
+ }
113
+ )
114
+
115
+ expect do
116
+ @instance.otp_sign_in(
117
+ method: DeliveryMethod::VOICE,
118
+ login_id: '+12122242225',
80
119
  login_options: {
81
120
  stepup: false,
82
121
  custom_claims: { 'abc': '123' },
@@ -89,6 +128,7 @@ describe Descope::Api::V1::OTP do
89
128
  end
90
129
  end
91
130
 
131
+ # Sign Up methods
92
132
  context '.sign_up' do
93
133
  it 'is expected to respond to otp email sign up' do
94
134
  expect(@instance).to respond_to(:otp_sign_up)
@@ -96,7 +136,7 @@ describe Descope::Api::V1::OTP do
96
136
 
97
137
  it 'is expected to sign up with otp via email' do
98
138
  request_params = {
99
- loginId: 'test',
139
+ loginId: 'user1',
100
140
  user: { loginId: 'user1', email: 'dummy@dummy.com' },
101
141
  email: 'dummy@dummy.com'
102
142
  }
@@ -110,18 +150,18 @@ describe Descope::Api::V1::OTP do
110
150
 
111
151
  expect do
112
152
  @instance.otp_sign_up(
113
- login_id: 'test',
153
+ login_id: 'user1',
114
154
  method: DeliveryMethod::EMAIL,
115
155
  user: { login_id: 'user1', email: 'dummy@dummy.com' }
116
156
  )
117
157
  end.not_to raise_error
118
158
  end
119
159
 
120
- it 'is expected to sign up with otp via phone' do
160
+ it 'is expected to sign up with otp via SMS' do
121
161
  request_params = {
122
- loginId: 'test',
123
- user: { loginId: 'user1', phone: '+1234567890' },
124
- phone: '+1234567890'
162
+ loginId: '+1234567890',
163
+ user: { loginId: '+1234567890' },
164
+ phone: ''
125
165
  }
126
166
 
127
167
  expect(@instance).to receive(:post).with(
@@ -133,22 +173,46 @@ describe Descope::Api::V1::OTP do
133
173
 
134
174
  expect do
135
175
  @instance.otp_sign_up(
136
- login_id: 'test',
176
+ login_id: '+1234567890',
137
177
  method: DeliveryMethod::SMS,
138
- user: { login_id: 'user1', phone: '+1234567890' }
178
+ user: { login_id: '+1234567890' }
179
+ )
180
+ end.not_to raise_error
181
+ end
182
+
183
+ it 'is expected to sign up with otp via Voice' do
184
+ request_params = {
185
+ loginId: '+1234567890',
186
+ user: { loginId: '+1234567890', phone: '+1234567890' },
187
+ phone: '+1234567890'
188
+ }
189
+
190
+ expect(@instance).to receive(:post).with(
191
+ otp_compose_signup_url(DeliveryMethod::VOICE),
192
+ request_params
193
+ ).and_return({ 'maskedPhone' => '+1******890' })
194
+
195
+ allow_any_instance_of(Descope::Api::V1::Auth).to receive(:extract_masked_address).and_return({})
196
+
197
+ expect do
198
+ @instance.otp_sign_up(
199
+ login_id: '+1234567890',
200
+ method: DeliveryMethod::VOICE,
201
+ user: { login_id: '+1234567890', phone: '+1234567890' }
139
202
  )
140
203
  end.not_to raise_error
141
204
  end
142
205
  end
143
206
 
207
+ # Sign Up or In methods
144
208
  context '.sign_up_or_in' do
145
209
  it 'is expected to respond to sign up' do
146
210
  expect(@instance).to respond_to(:otp_sign_up_or_in)
147
211
  end
148
212
 
149
- it 'is expected to sign up or in with otp' do
213
+ it 'is expected to sign up or in with otp via email' do
150
214
  request_params = {
151
- loginId: 'test',
215
+ loginId: 'dummy@dummy.com',
152
216
  loginOptions: {
153
217
  stepup: false,
154
218
  customClaims: { 'abc': '123' },
@@ -168,7 +232,79 @@ describe Descope::Api::V1::OTP do
168
232
  expect do
169
233
  @instance.otp_sign_up_or_in(
170
234
  method: DeliveryMethod::EMAIL,
171
- login_id: 'test',
235
+ login_id: 'dummy@dummy.com',
236
+ login_options: {
237
+ stepup: false,
238
+ custom_claims: { 'abc': '123' },
239
+ mfa: false,
240
+ sso_app_id: 'sso-id'
241
+ },
242
+ provider_id: 'provider-id',
243
+ template_id: 'template-id',
244
+ sso_app_id: 'sso-id'
245
+ )
246
+ end.not_to raise_error
247
+ end
248
+
249
+ it 'is expected to sign up or in with otp via SMS' do
250
+ request_params = {
251
+ loginId: '+12122242225',
252
+ loginOptions: {
253
+ stepup: false,
254
+ customClaims: { 'abc': '123' },
255
+ mfa: false,
256
+ ssoAppId: 'sso-id'
257
+ },
258
+ providerId: 'provider-id',
259
+ templateId: 'template-id',
260
+ ssoAppId: 'sso-id'
261
+ }
262
+
263
+ expect(@instance).to receive(:post).with(
264
+ otp_compose_sign_up_or_in_url(DeliveryMethod::SMS),
265
+ request_params
266
+ ).and_return({ 'maskedPhone' => '+1******890' })
267
+
268
+ expect do
269
+ @instance.otp_sign_up_or_in(
270
+ method: DeliveryMethod::SMS,
271
+ login_id: '+12122242225',
272
+ login_options: {
273
+ stepup: false,
274
+ custom_claims: { 'abc': '123' },
275
+ mfa: false,
276
+ sso_app_id: 'sso-id'
277
+ },
278
+ provider_id: 'provider-id',
279
+ template_id: 'template-id',
280
+ sso_app_id: 'sso-id'
281
+ )
282
+ end.not_to raise_error
283
+ end
284
+
285
+ it 'is expected to sign up or in with otp via Voice' do
286
+ request_params = {
287
+ loginId: '+12122242225',
288
+ loginOptions: {
289
+ stepup: false,
290
+ customClaims: { 'abc': '123' },
291
+ mfa: false,
292
+ ssoAppId: 'sso-id'
293
+ },
294
+ providerId: 'provider-id',
295
+ templateId: 'template-id',
296
+ ssoAppId: 'sso-id'
297
+ }
298
+
299
+ expect(@instance).to receive(:post).with(
300
+ otp_compose_sign_up_or_in_url(DeliveryMethod::VOICE),
301
+ request_params
302
+ ).and_return({ 'maskedPhone' => '+1******890' })
303
+
304
+ expect do
305
+ @instance.otp_sign_up_or_in(
306
+ method: DeliveryMethod::VOICE,
307
+ login_id: '+12122242225',
172
308
  login_options: {
173
309
  stepup: false,
174
310
  custom_claims: { 'abc': '123' },
@@ -215,6 +351,28 @@ describe Descope::Api::V1::OTP do
215
351
  expect(@instance).to respond_to(:otp_update_user_email)
216
352
  end
217
353
 
354
+ it 'raises a validation error' do
355
+ expect { OTP.otp_update_user_phone(login_id: nil) }
356
+ .to raise_error('login_id cannot be empty')
357
+ end
358
+
359
+ it 'raises a validation error' do
360
+ expect { OTP.otp_update_user_phone(login_id: 'someone', phone: nil) }
361
+ .to raise_error('Phone number cannot be empty')
362
+ end
363
+
364
+ it 'raises a delivery method error with invalid method' do
365
+ expect do
366
+ OTP.otp_update_user_phone(login_id: 'abc', phone: '+12124332222', method: 0)
367
+ end.to raise_error(Descope::AuthException, /Delivery method should be one of the following/)
368
+ end
369
+
370
+ it 'raises a validation error when phone number doesnt match pattern' do
371
+ expect do
372
+ OTP.otp_update_user_phone(login_id: 'abc', phone: '-1212a$', method: DeliveryMethod::SMS)
373
+ end.to raise_error(Descope::AuthException, /Invalid pattern for phone number/)
374
+ end
375
+
218
376
  it 'is expected to update email with otp' do
219
377
  request_params = {
220
378
  loginId: 'test',
@@ -43,9 +43,18 @@ describe Descope::Api::V1::Password do
43
43
  end
44
44
 
45
45
  it 'is expected to sign in with password' do
46
+ response_body = {
47
+ 'sessionJwt' => 'fake_session_jwt',
48
+ 'refreshJwt' => 'fake_refresh_jwt',
49
+ 'cookies' => {
50
+ 'refresh_token' => 'fake_refresh_cookie'
51
+ }
52
+ }
53
+
46
54
  expect(@instance).to receive(:post).with(
47
55
  SIGN_IN_PASSWORD_PATH, { loginId: 'test', password: 's3cr3t', ssoAppId: nil }
48
- )
56
+ ).and_return(response_body)
57
+
49
58
  # stub the jwt_get_unverified_header method to return the kid of the public key created above
50
59
  allow(@instance).to receive(:generate_jwt_response).and_return({})
51
60
  expect { @instance.password_sign_in(login_id: 'test', password: 's3cr3t') }.not_to raise_error