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
@@ -67,7 +67,9 @@ module Descope
67
67
  def enchanted_link_get_session(pending_ref = nil)
68
68
  # @see https://docs.descope.com/api/openapi/enchantedlink/operation/GetEnchantedLinkSession/
69
69
  res = post(GET_SESSION_ENCHANTEDLINK_AUTH_PATH, { pendingRef: pending_ref })
70
- generate_jwt_response(response_body: res, refresh_cookie: res['refreshJwt'])
70
+ cookies = res.fetch(COOKIE_DATA_NAME, nil) || res.fetch('cookies', {})
71
+ refresh_cookie = cookies.fetch(REFRESH_SESSION_COOKIE_NAME, nil) || res.fetch('refreshJwt', nil)
72
+ generate_jwt_response(response_body: res, refresh_cookie:)
71
73
  end
72
74
 
73
75
  private
@@ -42,7 +42,9 @@ module Descope
42
42
  def magiclink_verify_token(token = nil)
43
43
  validate_token_not_empty(token)
44
44
  res = post(VERIFY_MAGICLINK_AUTH_PATH, { token: })
45
- generate_jwt_response(response_body: res)
45
+ cookies = res.fetch(COOKIE_DATA_NAME, nil) || res.fetch('cookies', {})
46
+ refresh_cookie = cookies.fetch(REFRESH_SESSION_COOKIE_NAME, nil) || res.fetch('refreshJwt', nil)
47
+ generate_jwt_response(response_body: res, refresh_cookie:)
46
48
  end
47
49
 
48
50
  def magiclink_update_user_email(login_id: nil, email: nil, uri: nil, add_to_login_ids: nil, on_merge_use_existing: nil, provider_id: nil, template_id: nil, template_options: nil, refresh_token: nil)
@@ -10,10 +10,11 @@ module Descope
10
10
  include Descope::Mixins::Common::EndpointsV1
11
11
  include Descope::Mixins::Common::EndpointsV2
12
12
 
13
- def otp_sign_in(method: nil, login_id: nil, login_options: nil, refresh_token: nil, provider_id: nil,
13
+ def otp_sign_in(method: nil, login_id: nil, login_options: nil, refresh_token: nil, provider_id: nil,
14
14
  template_id: nil, sso_app_id: nil)
15
- # Sign in (log in) an existing user with the unique login_id you provide. (See 'sign_up' function for an explanation of the
16
- # login_id field.) Provide the DeliveryMethod required for this user. If the login_id value cannot be used for the
15
+ # Sign in (log in) an existing user with the unique login_id you provide.
16
+ # The login_id field is used to identify the user. It can be an email address or a phone number.
17
+ # Provide the DeliveryMethod required for this user. If the login_id value cannot be used for the
17
18
  # DeliverMethod selected (for example, 'login_id = 4567qq445km' and 'DeliveryMethod = email')
18
19
  validate_login_id(login_id)
19
20
  uri = otp_compose_signin_url(method)
@@ -23,12 +24,15 @@ module Descope
23
24
  end
24
25
 
25
26
  def otp_sign_up(method: nil, login_id: nil, user: {}, provider_id: nil, template_id: nil)
26
- # Sign up (create) a new user using their email or phone number. Choose a delivery method for OTP
27
- # verification, for example email, SMS, or WhatsApp.
27
+ # Sign up (create) a new user using their email or phone number.
28
+ # The login_id field is used to identify the user. It can be an email address or a phone number.
29
+ # Choose a delivery method for OTP verification, for example email, SMS, or Voice.
28
30
  # (optional) Include additional user metadata that you wish to preserve.
29
- user ||= {}
31
+ validate_login_id(login_id)
30
32
 
31
- raise AuthException unless adjust_and_verify_delivery_method(method, login_id, user)
33
+ unless adjust_and_verify_delivery_method(method, login_id, user)
34
+ raise Descope::AuthException.new('Could not verify delivery method', code: 400)
35
+ end
32
36
 
33
37
  uri = otp_compose_signup_url(method)
34
38
  body = otp_compose_signup_body(method, login_id, user, provider_id, template_id)
@@ -38,9 +42,11 @@ module Descope
38
42
 
39
43
  def otp_sign_up_or_in(method: nil, login_id: nil, login_options: nil, provider_id: nil, template_id: nil,
40
44
  sso_app_id: nil)
41
- # Sign_up_or_in lets you handle both sign up and sign in with a single call. Sign-up_or_in will first
42
- # determine if login_id is a new or existing end user. If login_id is new, a new end user user will be
43
- # created and then authenticated using the OTP DeliveryMethod specified.
45
+ # Sign_up_or_in lets you handle both sign up and sign in with a single call.
46
+ # The login_id field is used to identify the user. It can be an email address or a phone number.
47
+ # Sign-up_or_in will first determine if login_id is a new or existing end user.
48
+ # If login_id is new, a new end user user will be created and then authenticated using the
49
+ # OTP DeliveryMethod specified.
44
50
  # If login_id exists, the end user will be authenticated using the OTP DeliveryMethod specified.
45
51
  validate_login_id(login_id)
46
52
  uri = otp_compose_sign_up_or_in_url(method)
@@ -57,7 +63,9 @@ module Descope
57
63
  code:
58
64
  }
59
65
  res = post(uri, request_params)
60
- generate_jwt_response(response_body: res, refresh_cookie: res.fetch('refreshJwt', {}))
66
+ cookies = res.fetch(COOKIE_DATA_NAME, nil) || res.fetch('cookies', {})
67
+ refresh_cookie = cookies.fetch(REFRESH_SESSION_COOKIE_NAME, nil) || res.fetch('refreshJwt', nil)
68
+ generate_jwt_response(response_body: res, refresh_cookie:)
61
69
  end
62
70
 
63
71
  def otp_update_user_email(login_id: nil, email: nil, refresh_token: nil, add_to_login_ids: false,
@@ -81,9 +89,10 @@ module Descope
81
89
  method: nil, login_id: nil, phone: nil, refresh_token: nil, add_to_login_ids: false,
82
90
  on_merge_use_existing: false, provider_id: nil, template_id: nil
83
91
  )
84
- # Update the phone number of an existing end user, after verifying the authenticity of the end user using OTP.
92
+ # Update the phone number of an existing end user, after verifying the authenticity of the end user using OTP
85
93
  validate_login_id(login_id)
86
94
  validate_phone(method, phone)
95
+
87
96
  uri = otp_compose_update_phone_url(method)
88
97
  request_params = {
89
98
  loginId: login_id,
@@ -127,7 +136,7 @@ module Descope
127
136
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
128
137
  def otp_compose_signup_body(method, login_id, user, provider_id, template_id)
129
138
  body = {
130
- loginId: login_id,
139
+ loginId: login_id
131
140
  }
132
141
 
133
142
  unless user.nil?
@@ -167,7 +176,8 @@ module Descope
167
176
  end
168
177
 
169
178
  private
170
- def otp_user_compose_update_body(login_id: nil, name: nil, phone: nil, email: nil, given_name: nil, middle_name: nil, family_name: nil)
179
+ def otp_user_compose_update_body(login_id: nil, name: nil, phone: nil, email: nil, given_name: nil,
180
+ middle_name: nil, family_name: nil)
171
181
  user = {}
172
182
  user[:loginId] = login_id if login_id
173
183
  user[:name] = name if name
@@ -176,7 +186,6 @@ module Descope
176
186
  user[:givenName] = given_name if given_name
177
187
  user[:middleName] = middle_name if middle_name
178
188
  user[:familyName] = family_name if family_name
179
-
180
189
  user
181
190
  end
182
191
  end
@@ -22,7 +22,9 @@ module Descope
22
22
 
23
23
  request_params[:user] = password_user_compose_update_body(**user) unless user.nil?
24
24
  res = post(SIGN_UP_PASSWORD_PATH, request_params)
25
- generate_jwt_response(response_body: res)
25
+ cookies = res.fetch(COOKIE_DATA_NAME, nil) || res.fetch('cookies', {})
26
+ refresh_cookie = cookies.fetch(REFRESH_SESSION_COOKIE_NAME, nil) || res.fetch('refreshJwt', nil)
27
+ generate_jwt_response(response_body: res, refresh_cookie:)
26
28
  end
27
29
 
28
30
  def password_sign_in(login_id: nil, password: nil, sso_app_id: nil)
@@ -38,7 +40,9 @@ module Descope
38
40
  ssoAppId: sso_app_id
39
41
  }
40
42
  res = post(SIGN_IN_PASSWORD_PATH, request_params)
41
- generate_jwt_response(response_body: res)
43
+ cookies = res.fetch(COOKIE_DATA_NAME, nil) || res.fetch('cookies', {})
44
+ refresh_cookie = cookies.fetch(REFRESH_SESSION_COOKIE_NAME, nil) || res.fetch('refreshJwt', nil)
45
+ generate_jwt_response(response_body: res, refresh_cookie:)
42
46
  end
43
47
 
44
48
  def password_replace(login_id: nil, old_password: nil, new_password: nil)
@@ -17,7 +17,9 @@ module Descope
17
17
  uri = VERIFY_TOTP_PATH
18
18
  body = totp_compose_signin_body(login_id, code, login_options)
19
19
  res = post(uri, body, {}, nil)
20
- generate_jwt_response(response_body: res, refresh_cookie: res.fetch('refreshJwt', {}))
20
+ cookies = res.fetch(COOKIE_DATA_NAME, nil) || res.fetch('cookies', {})
21
+ refresh_cookie = cookies.fetch(REFRESH_SESSION_COOKIE_NAME, nil) || res.fetch('refreshJwt', nil)
22
+ generate_jwt_response(response_body: res, refresh_cookie:)
21
23
  end
22
24
 
23
25
  def totp_sign_up(login_id: nil, user: nil, sso_app_id: nil)
@@ -34,7 +34,6 @@ module Descope
34
34
  end
35
35
 
36
36
  jwt_response = generate_auth_info(response_body, refresh_cookie, true, audience)
37
- @logger.debug "jwt_response: #{jwt_response}"
38
37
  jwt_response['user'] = response_body.key?('user') ? response_body['user'] : {}
39
38
  jwt_response['firstSeen'] = response_body.key?('firstSeen') ? response_body['firstSeen'] : true
40
39
 
@@ -51,10 +50,10 @@ module Descope
51
50
  # Return value (Hash): returns the session token from the server together with the expiry and key id
52
51
  # (sessionToken:Hash, keyId:str, expiration:int)
53
52
  unless (access_key.is_a?(String) || access_key.nil?) && !access_key.to_s.empty?
54
- raise Descope::AuthException, 'Access key should be a string!'
53
+ raise AuthException.new('Access key should be a string!', code: 400)
55
54
  end
56
55
 
57
- res = post(EXCHANGE_AUTH_ACCESS_KEY_PATH, { loginOptions: login_options, audience: }, {}, access_key)
56
+ res = post(EXCHANGE_AUTH_ACCESS_KEY_PATH, { loginOptions: login_options, audience: audience }, {}, access_key)
58
57
  generate_auth_info(res, nil, false, audience)
59
58
  end
60
59
 
@@ -62,6 +61,8 @@ module Descope
62
61
  validate_refresh_token_not_nil(refresh_token)
63
62
  res = post(SELECT_TENANT_PATH, { tenantId: tenant_id }, {}, refresh_token)
64
63
  @logger.debug "select_tenant response: #{res}"
64
+ cookies = res.fetch('cookies')
65
+ generate_jwt_response(response_body: res, refresh_cookie: cookies.fetch(REFRESH_SESSION_COOKIE_NAME, nil))
65
66
  generate_jwt_response(
66
67
  response_body: res,
67
68
  refresh_cookie: res['refreshJwt']
@@ -71,7 +72,7 @@ module Descope
71
72
  def validate_permissions(jwt_response: nil, permissions: nil)
72
73
  # Validate that a jwt_response has been granted the specified permissions.
73
74
  # For a multi-tenant environment use validate_tenant_permissions function
74
- validate_tenant_permissions(jwt_response:, permissions:)
75
+ validate_tenant_permissions(jwt_response: jwt_response, permissions: permissions)
75
76
  end
76
77
 
77
78
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
@@ -122,7 +123,7 @@ module Descope
122
123
  def validate_roles(jwt_response: nil, roles: nil)
123
124
  # Validate that a jwt_response has been granted the specified roles.
124
125
  # For a multi-tenant environment use validate_tenant_roles function
125
- validate_tenant_roles(jwt_response:, tenant: '', roles:)
126
+ validate_tenant_roles(jwt_response: jwt_response, tenant: '', roles: roles)
126
127
  end
127
128
 
128
129
  def validate_tenant_roles(jwt_response: nil, tenant: nil, roles: nil)
@@ -231,24 +232,58 @@ module Descope
231
232
  private
232
233
 
233
234
  def generate_auth_info(response_body, refresh_token, user_jwt, audience = nil)
234
- @logger.debug "generating auth info: #{response_body}, #{refresh_token}, #{user_jwt}, #{audience}"
235
+ @logger.debug "generating auth info: response_body: #{response_body}, refresh_token: #{refresh_token}, user_jwt: #{user_jwt}, audience: #{audience}"
235
236
  jwt_response = {}
236
237
 
237
238
  # validate the session token if sessionJwt is not empty
238
239
  st_jwt = response_body.fetch('sessionJwt', '')
239
240
  unless st_jwt.empty?
240
- @logger.debug "validating session token with refresh_token: #{refresh_token}" if st_jwt
241
- jwt_response[SESSION_TOKEN_NAME] = validate_token(st_jwt, audience) if st_jwt
241
+ @logger.debug 'found sessionJwt in response body, adding to jwt_response'
242
+ jwt_response[SESSION_TOKEN_NAME] = validate_token(st_jwt, audience)
243
+ end
244
+
245
+ # Check for session token in cookies if not found in response body
246
+ cookies = response_body.fetch('cookies', {})
247
+ if jwt_response[SESSION_TOKEN_NAME].nil?
248
+ cookies.each do |cookie_name, cookie_value|
249
+ if cookie_name == SESSION_COOKIE_NAME
250
+ @logger.debug "found session token in cookies with name #{cookie_name}, adding to jwt_response"
251
+ jwt_response[SESSION_TOKEN_NAME] = validate_token(cookie_value, audience)
252
+ break
253
+ end
254
+ end
242
255
  end
243
256
 
244
257
  # validate refresh token if refresh_token was passed or if refreshJwt is not empty
245
258
  rt_jwt = response_body.fetch('refreshJwt', '')
246
259
 
247
- if !refresh_token.nil? || !refresh_token.to_s.empty?
248
- @logger.debug "validating refresh token: #{refresh_token}" if refresh_token
249
- jwt_response[REFRESH_SESSION_TOKEN_NAME] = validate_token(refresh_token, audience)
250
- elsif !rt_jwt.empty?
260
+ if !rt_jwt.empty?
261
+ @logger.debug 'found refreshJwt in response body, adding to jwt_response'
262
+ @logger.debug 'validating refreshJwt token...'
251
263
  jwt_response[REFRESH_SESSION_TOKEN_NAME] = validate_token(rt_jwt, audience)
264
+ else
265
+ # Check cookies for refresh token
266
+ refresh_cookie_found = false
267
+ cookies.each do |cookie_name, cookie_value|
268
+ if cookie_name == REFRESH_SESSION_COOKIE_NAME && !cookie_value.to_s.empty?
269
+ @logger.debug "found refresh token in cookies with name #{cookie_name}, adding to jwt_response"
270
+ jwt_response[REFRESH_SESSION_TOKEN_NAME] = validate_token(cookie_value, audience)
271
+ refresh_cookie_found = true
272
+ break
273
+ end
274
+ end
275
+
276
+ # If not found in cookies, check if refresh_token parameter was passed
277
+ if !refresh_cookie_found && refresh_token && !refresh_token.to_s.empty?
278
+ @logger.debug 'refresh token not found in cookies, but refresh_token was passed, adding to jwt_response'
279
+ @logger.debug 'validating passed-in refresh token...'
280
+ jwt_response[REFRESH_SESSION_TOKEN_NAME] = validate_token(refresh_token, audience)
281
+ end
282
+ end
283
+
284
+ if jwt_response[REFRESH_SESSION_TOKEN_NAME].nil?
285
+ @logger.debug "Error: Could not find refreshJwt in response body: #{response_body} / cookies: #{cookies} / passed in refresh_token ->#{refresh_token}<-"
286
+ raise Descope::AuthException.new('Could not find refreshJwt in response body / cookies / passed in refresh_token', code: 500)
252
287
  end
253
288
 
254
289
  jwt_response = adjust_properties(jwt_response, user_jwt)
@@ -407,6 +442,7 @@ module Descope
407
442
  login_id = {
408
443
  DeliveryMethod::WHATSAPP => ['whatsapp', user.fetch(:phone, '')],
409
444
  DeliveryMethod::SMS => ['phone', user.fetch(:phone, '')],
445
+ DeliveryMethod::VOICE => ['phone', user.fetch(:phone, '')],
410
446
  DeliveryMethod::EMAIL => ['email', user.fetch(:email, '')]
411
447
  }[method]
412
448
 
@@ -416,34 +452,30 @@ module Descope
416
452
  end
417
453
 
418
454
  def adjust_and_verify_delivery_method(method, login_id, user)
419
- return false if login_id.nil?
455
+ @logger.debug("adjust_and_verify_delivery_method: method: #{method}, login_id: #{login_id}, user: #{user}")
456
+ raise AuthException.new("Could not verify delivery method for method: #{method}", code: 400) if method.nil?
457
+ raise AuthException.new('Could not verify delivery method without login_id', code: 400) if login_id.nil?
420
458
 
421
- return false unless user.is_a?(Hash)
459
+ unless user.is_a?(Hash)
460
+ raise AuthException.new('Could not verify delivery method, user is not a Hash', code: 400)
461
+ end
422
462
 
423
463
  case method
424
464
  when DeliveryMethod::EMAIL
425
- user[:email] ||= login_id
426
- begin
427
- validate_email(user[:email])
428
- return true
429
- rescue AuthException
430
- return false
431
- end
432
- when DeliveryMethod::SMS
433
- user[:phone] ||= login_id
434
- return false unless /^#{PHONE_REGEX}$/.match(user[:phone])
435
- when DeliveryMethod::WHATSAPP
436
- user[:phone] ||= login_id
437
- return false unless /^#{PHONE_REGEX}$/.match(user[:phone])
465
+ validate_email(login_id)
466
+ @logger.debug("email: #{login_id} is valid")
467
+ true
468
+ when DeliveryMethod::SMS, DeliveryMethod::WHATSAPP, DeliveryMethod::VOICE
469
+ validate_phone(method, login_id)
470
+ @logger.debug("phone number (login_id): #{login_id} is valid")
471
+ true
438
472
  else
439
- return false
473
+ false
440
474
  end
441
-
442
- true
443
475
  end
444
476
 
445
477
  def extract_masked_address(response, method)
446
- if [DeliveryMethod::SMS, DeliveryMethod::WHATSAPP].include?(method)
478
+ if [DeliveryMethod::SMS, DeliveryMethod::WHATSAPP, DeliveryMethod::VOICE].include?(method)
447
479
  response['maskedPhone']
448
480
  elsif method == DeliveryMethod::EMAIL
449
481
  response['maskedEmail']
@@ -455,7 +487,7 @@ module Descope
455
487
  def exchange_token(uri, code)
456
488
  raise Descope::ArgumentException.new("Code can't be empty", code: 400) if code.nil? || code.empty?
457
489
 
458
- res = post(uri, { code: })
490
+ res = post(uri, { code: code })
459
491
  generate_jwt_response(
460
492
  response_body: res,
461
493
  refresh_cookie: res['refreshJwt']
@@ -58,6 +58,30 @@ module Descope
58
58
  { 'audits' => res['audits'].map { |audit| convert_audit_record(audit) } }
59
59
  end
60
60
 
61
+ def audit_create_event(action: nil, type: nil, data: nil, user_id: nil, actor_id: nil, tenant_id: nil)
62
+ # Create an audit event
63
+ unless %w[info warn error].include?(type)
64
+ raise Descope::AuthException, 'type must be either info, warn or error'
65
+ end
66
+
67
+ # validation
68
+ raise Descope::AuthException, 'data must be provided as a key, value Hash' unless data.is_a?(Hash)
69
+ raise Descope::AuthException, 'action must be provided' if action.nil?
70
+ raise Descope::AuthException, 'actor_id must be provided' if actor_id.nil?
71
+ raise Descope::AuthException, 'tenant_id must be provided' if tenant_id.nil?
72
+
73
+ request_params = {
74
+ action:,
75
+ tenantId: tenant_id,
76
+ type:,
77
+ actorId: actor_id,
78
+ data:
79
+ }
80
+ request_params[:userId] = user_id unless user_id.nil?
81
+
82
+ post(AUDIT_CREATE_EVENT, request_params)
83
+ end
84
+
61
85
  private
62
86
 
63
87
  def convert_audit_record(audit)
@@ -17,6 +17,7 @@ module Descope
17
17
 
18
18
  # user
19
19
  USER_CREATE_PATH = '/v1/mgmt/user/create'
20
+ TEST_USER_CREATE_PATH = '/v1/mgmt/user/create/test'
20
21
  USER_CREATE_BATCH_PATH = '/v1/mgmt/user/create/batch'
21
22
  USER_UPDATE_PATH = '/v1/mgmt/user/update'
22
23
  USER_DELETE_PATH = '/v1/mgmt/user/delete'
@@ -37,6 +38,8 @@ module Descope
37
38
  USER_SET_TEMPORARY_PASSWORD_PATH = '/v1/mgmt/user/password/set/temporary'
38
39
  USER_SET_ACTIVE_PASSWORD_PATH = '/v1/mgmt/user/password/set/active'
39
40
  USER_SET_PASSWORD_PATH = '/v1/mgmt/user/password/set'
41
+ USER_SEARCH_PATH = "/v2/mgmt/user/search"
42
+ TEST_USERS_SEARCH_PATH = "/v2/mgmt/user/search/test"
40
43
  USER_EXPIRE_PASSWORD_PATH = '/v1/mgmt/user/password/expire'
41
44
  USER_ADD_TENANT_PATH = '/v1/mgmt/user/update/tenant/add'
42
45
  USER_REMOVE_TENANT_PATH = '/v1/mgmt/user/update/tenant/remove'
@@ -44,6 +47,7 @@ module Descope
44
47
  USER_GENERATE_MAGIC_LINK_FOR_TEST_PATH = '/v1/mgmt/tests/generate/magiclink'
45
48
  USER_GENERATE_ENCHANTED_LINK_FOR_TEST_PATH = '/v1/mgmt/tests/generate/enchantedlink'
46
49
  USER_GENERATE_EMBEDDED_LINK_PATH = '/v1/mgmt/user/signin/embeddedlink'
50
+ USER_PATCH_PATH = '/v1/mgmt/user/patch'
47
51
 
48
52
  # access key
49
53
  ACCESS_KEY_CREATE_PATH = '/v1/mgmt/accesskey/create'
@@ -54,13 +58,24 @@ module Descope
54
58
  ACCESS_KEY_ACTIVATE_PATH = '/v1/mgmt/accesskey/activate'
55
59
  ACCESS_KEY_DELETE_PATH = '/v1/mgmt/accesskey/delete'
56
60
 
57
- # sso
61
+ # sso application
62
+ SSO_APPLICATION_OIDC_CREATE_PATH = '/v1/mgmt/sso/idp/app/oidc/create'
63
+ SSO_APPLICATION_SAML_CREATE_PATH = '/v1/mgmt/sso/idp/app/saml/create'
64
+ SSO_APPLICATION_OIDC_UPDATE_PATH = '/v1/mgmt/sso/idp/app/oidc/update'
65
+ SSO_APPLICATION_SAML_UPDATE_PATH = '/v1/mgmt/sso/idp/app/saml/update'
66
+ SSO_APPLICATION_DELETE_PATH = '/v1/mgmt/sso/idp/app/delete'
67
+ SSO_APPLICATION_LOAD_PATH = '/v1/mgmt/sso/idp/app/load'
68
+ SSO_APPLICATION_LOAD_ALL_PATH = '/v1/mgmt/sso/idp/apps/load'
69
+
70
+ # sso settings
58
71
  SSO_SETTINGS_PATH = '/v2/mgmt/sso/settings'
72
+ SSO_METADATA_PATH = '/v1/mgmt/sso/metadata'
73
+ SSO_MAPPING_PATH = '/v1/mgmt/sso/mapping'
74
+ SSO_LOAD_SETTINGS_PATH = '/v2/mgmt/sso/settings' # v2 only
59
75
  SSO_OIDC_PATH = '/v1/mgmt/sso/oidc' # configure ssp settings via oidc
60
- SSO_OIDC_CREATE_APP_PATH = '/v1/mgmt/sso/idp/app/oidc/create'
61
- SSO_OIDC_UPDATE_APP_PATH = '/v1/mgmt/sso/idp/app/oidc/create'
62
- SSO_SAML_PATH = '/v1/mgmt/sso/saml' # configure ssp settings via saml
63
- SSO_SAML_METADATA_PATH = '/v1/mgmt/sso/saml/metadata' # configure ssp settings via saml metadata
76
+ SSO_CONFIGURE_OIDC_SETTINGS_PATH = '/v1/mgmt/sso/oidc'
77
+ SSO_CONFIGURE_SAML_SETTINGS_PATH = '/v1/mgmt/sso/saml'
78
+ SSO_CONFIGURE_SAML_METADATA_PATH = '/v1/mgmt/sso/saml/metadata'
64
79
 
65
80
  # SCIM
66
81
  SCIM_GROUPS_PATH = '/scim/v2/Groups'
@@ -100,6 +115,7 @@ module Descope
100
115
 
101
116
  # Audit
102
117
  AUDIT_SEARCH = '/v1/mgmt/audit/search'
118
+ AUDIT_CREATE_EVENT = '/v1/mgmt/audit/event'
103
119
 
104
120
  # Authz ReBAC
105
121
  AUTHZ_SCHEMA_SAVE = '/v1/mgmt/authz/schema/save'