kinde_sdk 1.1.1 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +113 -19
  3. data/kinde_api/README.md +58 -23
  4. data/kinde_api/docs/AddOrganizationUsersRequest.md +1 -1
  5. data/kinde_api/docs/AddOrganizationUsersRequestUsersInner.md +22 -0
  6. data/kinde_api/docs/{AddOrganizationUsers200Response.md → AddOrganizationUsersResponse.md} +2 -2
  7. data/kinde_api/docs/Application.md +20 -0
  8. data/kinde_api/docs/CallbacksApi.md +219 -0
  9. data/kinde_api/docs/ConnectedAppsApi.md +9 -9
  10. data/kinde_api/docs/CreateOrganizationRequest.md +11 -1
  11. data/kinde_api/docs/CreateOrganizationResponse.md +22 -0
  12. data/kinde_api/docs/CreateOrganizationResponseOrganization.md +18 -0
  13. data/kinde_api/docs/CreateOrganizationUserRoleRequest.md +18 -0
  14. data/kinde_api/docs/CreatePermissionRequest.md +22 -0
  15. data/kinde_api/docs/CreateRoleRequest.md +24 -0
  16. data/kinde_api/docs/CreateSubscriberSuccessResponse.md +18 -0
  17. data/kinde_api/docs/CreateSubscriberSuccessResponseSubscriber.md +18 -0
  18. data/kinde_api/docs/{CreateUser200Response.md → CreateUserResponse.md} +2 -2
  19. data/kinde_api/docs/EnvironmentsApi.md +71 -4
  20. data/kinde_api/docs/FeatureFlagsApi.md +9 -11
  21. data/kinde_api/docs/GetApplicationsResponse.md +24 -0
  22. data/kinde_api/docs/GetEnvironmentFeatureFlagsResponse.md +24 -0
  23. data/kinde_api/docs/GetOrganizationFeatureFlagsResponse.md +22 -0
  24. data/kinde_api/docs/GetOrganizationFeatureFlagsResponseFeatureFlagsValue.md +20 -0
  25. data/kinde_api/docs/{GetOrganizations200Response.md → GetOrganizationsResponse.md} +2 -2
  26. data/kinde_api/docs/GetOrganizationsUserRolesResponse.md +24 -0
  27. data/kinde_api/docs/{GetOrganizationUsers200Response.md → GetOrganizationsUsersResponse.md} +2 -2
  28. data/kinde_api/docs/GetRedirectCallbackUrlsResponse.md +18 -0
  29. data/kinde_api/docs/OrganizationUser.md +3 -1
  30. data/kinde_api/docs/OrganizationUserRole.md +22 -0
  31. data/kinde_api/docs/OrganizationsApi.md +494 -59
  32. data/kinde_api/docs/Permissions.md +22 -0
  33. data/kinde_api/docs/PermissionsApi.md +229 -0
  34. data/kinde_api/docs/RedirectCallbackUrls.md +18 -0
  35. data/kinde_api/docs/Roles.md +22 -0
  36. data/kinde_api/docs/RolesApi.md +229 -0
  37. data/kinde_api/docs/SubscribersApi.md +229 -0
  38. data/kinde_api/docs/UpdateOrganizationRequest.md +28 -0
  39. data/kinde_api/docs/UpdateOrganizationUsersRequest.md +18 -0
  40. data/kinde_api/docs/UpdateOrganizationUsersRequestUsersInner.md +24 -0
  41. data/kinde_api/docs/UpdateOrganizationUsersResponse.md +24 -0
  42. data/kinde_api/docs/UpdateUserRequest.md +3 -1
  43. data/kinde_api/docs/User.md +15 -1
  44. data/kinde_api/docs/UserIdentityResult.md +1 -3
  45. data/kinde_api/docs/UserProfile.md +3 -1
  46. data/kinde_api/docs/UserProfileV2.md +6 -2
  47. data/kinde_api/docs/UsersApi.md +31 -259
  48. data/kinde_api/docs/{GetUsers200Response.md → UsersResponse.md} +2 -2
  49. data/kinde_api/lib/kinde_api/api/callbacks_api.rb +221 -0
  50. data/kinde_api/lib/kinde_api/api/connected_apps_api.rb +8 -8
  51. data/kinde_api/lib/kinde_api/api/environments_api.rb +61 -4
  52. data/kinde_api/lib/kinde_api/api/feature_flags_api.rb +8 -15
  53. data/kinde_api/lib/kinde_api/api/organizations_api.rb +492 -57
  54. data/kinde_api/lib/kinde_api/api/permissions_api.rb +226 -0
  55. data/kinde_api/lib/kinde_api/api/roles_api.rb +226 -0
  56. data/kinde_api/lib/kinde_api/api/subscribers_api.rb +228 -0
  57. data/kinde_api/lib/kinde_api/api/users_api.rb +30 -233
  58. data/kinde_api/lib/kinde_api/api_client.rb +1 -13
  59. data/kinde_api/lib/kinde_api/configuration.rb +3 -77
  60. data/kinde_api/lib/kinde_api/models/add_organization_users_request.rb +2 -2
  61. data/kinde_api/lib/kinde_api/models/add_organization_users_request_users_inner.rb +242 -0
  62. data/kinde_api/lib/kinde_api/models/{add_organization_users200_response.rb → add_organization_users_response.rb} +3 -3
  63. data/kinde_api/lib/kinde_api/models/application.rb +226 -0
  64. data/kinde_api/lib/kinde_api/models/create_organization_request.rb +54 -4
  65. data/kinde_api/lib/kinde_api/models/{remove_organization_users200_response.rb → create_organization_response.rb} +19 -12
  66. data/kinde_api/lib/kinde_api/models/{create_organization201_response.rb → create_organization_response_organization.rb} +8 -18
  67. data/kinde_api/lib/kinde_api/models/create_organization_user_role_request.rb +218 -0
  68. data/kinde_api/lib/kinde_api/models/create_permission_request.rb +238 -0
  69. data/kinde_api/lib/kinde_api/models/create_role_request.rb +248 -0
  70. data/kinde_api/lib/kinde_api/models/create_subscriber_success_response.rb +217 -0
  71. data/kinde_api/lib/kinde_api/models/create_subscriber_success_response_subscriber.rb +218 -0
  72. data/kinde_api/lib/kinde_api/models/create_user_request_identities_inner.rb +34 -0
  73. data/kinde_api/lib/kinde_api/models/{create_user200_response.rb → create_user_response.rb} +3 -3
  74. data/kinde_api/lib/kinde_api/models/get_applications_response.rb +249 -0
  75. data/kinde_api/lib/kinde_api/models/get_environment_feature_flags_response.rb +250 -0
  76. data/kinde_api/lib/kinde_api/models/get_organization_feature_flags_response.rb +240 -0
  77. data/kinde_api/lib/kinde_api/models/get_organization_feature_flags_response_feature_flags_value.rb +260 -0
  78. data/kinde_api/lib/kinde_api/models/{get_organizations200_response.rb → get_organizations_response.rb} +3 -3
  79. data/kinde_api/lib/kinde_api/models/get_organizations_user_roles_response.rb +249 -0
  80. data/kinde_api/lib/kinde_api/models/{get_organization_users200_response.rb → get_organizations_users_response.rb} +3 -3
  81. data/kinde_api/lib/kinde_api/models/get_redirect_callback_urls_response.rb +220 -0
  82. data/kinde_api/lib/kinde_api/models/organization_user.rb +15 -4
  83. data/kinde_api/lib/kinde_api/models/organization_user_role.rb +235 -0
  84. data/kinde_api/lib/kinde_api/models/permissions.rb +238 -0
  85. data/kinde_api/lib/kinde_api/models/redirect_callback_urls.rb +220 -0
  86. data/kinde_api/lib/kinde_api/models/roles.rb +238 -0
  87. data/kinde_api/lib/kinde_api/models/update_organization_request.rb +268 -0
  88. data/kinde_api/lib/kinde_api/models/{remove_organization_users_request.rb → update_organization_users_request.rb} +5 -5
  89. data/kinde_api/lib/kinde_api/models/update_organization_users_request_users_inner.rb +252 -0
  90. data/kinde_api/lib/kinde_api/models/update_organization_users_response.rb +250 -0
  91. data/kinde_api/lib/kinde_api/models/update_user_request.rb +14 -4
  92. data/kinde_api/lib/kinde_api/models/user.rb +79 -5
  93. data/kinde_api/lib/kinde_api/models/user_identity_result.rb +4 -14
  94. data/kinde_api/lib/kinde_api/models/user_profile.rb +14 -4
  95. data/kinde_api/lib/kinde_api/models/user_profile_v2.rb +25 -5
  96. data/kinde_api/lib/kinde_api/models/{get_users200_response.rb → users_response.rb} +3 -3
  97. data/kinde_api/lib/kinde_api.rb +32 -8
  98. data/kinde_api/spec/api/callbacks_api_spec.rb +73 -0
  99. data/kinde_api/spec/api/connected_apps_api_spec.rb +1 -1
  100. data/kinde_api/spec/api/environments_api_spec.rb +11 -0
  101. data/kinde_api/spec/api/feature_flags_api_spec.rb +1 -2
  102. data/kinde_api/spec/api/organizations_api_spec.rb +93 -14
  103. data/kinde_api/spec/api/permissions_api_spec.rb +74 -0
  104. data/kinde_api/spec/api/roles_api_spec.rb +74 -0
  105. data/kinde_api/spec/api/subscribers_api_spec.rb +76 -0
  106. data/kinde_api/spec/api/users_api_spec.rb +6 -47
  107. data/kinde_api/spec/api_client_spec.rb +0 -12
  108. data/kinde_api/spec/models/add_organization_users_request_users_inner_spec.rb +46 -0
  109. data/kinde_api/spec/models/{add_organization_users200_response_spec.rb → add_organization_users_response_spec.rb} +6 -6
  110. data/kinde_api/spec/models/{remove_organization_users200_response_spec.rb → application_spec.rb} +8 -8
  111. data/kinde_api/spec/models/create_organization_request_spec.rb +30 -0
  112. data/kinde_api/spec/models/create_organization_response_organization_spec.rb +34 -0
  113. data/kinde_api/spec/models/{create_organization201_response_spec.rb → create_organization_response_spec.rb} +13 -7
  114. data/kinde_api/spec/models/create_organization_user_role_request_spec.rb +34 -0
  115. data/kinde_api/spec/models/create_permission_request_spec.rb +46 -0
  116. data/kinde_api/spec/models/create_role_request_spec.rb +52 -0
  117. data/kinde_api/spec/models/create_subscriber_success_response_spec.rb +34 -0
  118. data/kinde_api/spec/models/create_subscriber_success_response_subscriber_spec.rb +34 -0
  119. data/kinde_api/spec/models/create_user_request_identities_inner_spec.rb +4 -0
  120. data/kinde_api/spec/models/{create_user200_response_spec.rb → create_user_response_spec.rb} +6 -6
  121. data/kinde_api/spec/models/get_applications_response_spec.rb +52 -0
  122. data/kinde_api/spec/models/get_environment_feature_flags_response_spec.rb +52 -0
  123. data/kinde_api/spec/models/get_organization_feature_flags_response_feature_flags_value_spec.rb +44 -0
  124. data/kinde_api/spec/models/get_organization_feature_flags_response_spec.rb +46 -0
  125. data/kinde_api/spec/models/{get_organizations200_response_spec.rb → get_organizations_response_spec.rb} +6 -6
  126. data/kinde_api/spec/models/get_organizations_user_roles_response_spec.rb +52 -0
  127. data/kinde_api/spec/models/{get_organization_users200_response_spec.rb → get_organizations_users_response_spec.rb} +6 -6
  128. data/kinde_api/spec/models/get_redirect_callback_urls_response_spec.rb +34 -0
  129. data/kinde_api/spec/models/organization_user_role_spec.rb +46 -0
  130. data/kinde_api/spec/models/organization_user_spec.rb +6 -0
  131. data/kinde_api/spec/models/permissions_spec.rb +46 -0
  132. data/kinde_api/spec/models/redirect_callback_urls_spec.rb +34 -0
  133. data/kinde_api/spec/models/roles_spec.rb +46 -0
  134. data/kinde_api/spec/models/update_organization_request_spec.rb +64 -0
  135. data/kinde_api/spec/models/{remove_organization_users_request_spec.rb → update_organization_users_request_spec.rb} +6 -6
  136. data/kinde_api/spec/models/update_organization_users_request_users_inner_spec.rb +52 -0
  137. data/kinde_api/spec/models/update_organization_users_response_spec.rb +52 -0
  138. data/kinde_api/spec/models/update_user_request_spec.rb +6 -0
  139. data/kinde_api/spec/models/user_identity_result_spec.rb +0 -6
  140. data/kinde_api/spec/models/user_profile_spec.rb +6 -0
  141. data/kinde_api/spec/models/user_profile_v2_spec.rb +12 -0
  142. data/kinde_api/spec/models/user_spec.rb +42 -0
  143. data/kinde_api/spec/models/{get_users200_response_spec.rb → users_response_spec.rb} +6 -6
  144. data/kinde_sdk.gemspec +1 -1
  145. data/lib/kinde_sdk/client/feature_flags.rb +64 -0
  146. data/lib/kinde_sdk/client/permissions.rb +20 -0
  147. data/lib/kinde_sdk/client.rb +46 -19
  148. data/lib/kinde_sdk/configuration.rb +2 -2
  149. data/lib/kinde_sdk/version.rb +1 -1
  150. data/lib/kinde_sdk.rb +27 -12
  151. data/spec/kinde_sdk_spec.rb +161 -5
  152. data/spec/spec_helper.rb +2 -0
  153. metadata +134 -36
  154. data/kinde_api/docs/CreateOrganization201Response.md +0 -20
  155. data/kinde_api/docs/RemoveOrganizationUsers200Response.md +0 -20
  156. data/kinde_api/docs/RemoveOrganizationUsersRequest.md +0 -18
@@ -2,44 +2,71 @@ require "kinde_api"
2
2
 
3
3
  module KindeSdk
4
4
  class Client
5
- attr_accessor :kinde_api_client
6
- attr_accessor :bearer_token
5
+ include FeatureFlags
6
+ include Permissions
7
7
 
8
- def initialize(sdk_api_client, bearer_token)
8
+ attr_accessor :kinde_api_client, :auto_refresh_tokens, :bearer_token, :tokens_hash, :expires_at
9
+
10
+ def initialize(sdk_api_client, tokens_hash, auto_refresh_tokens)
9
11
  @kinde_api_client = sdk_api_client
10
- @bearer_token = bearer_token
11
- @decoded_token = JWT.decode(bearer_token, nil, false)
12
+ @auto_refresh_tokens = auto_refresh_tokens
13
+ set_hash_related_data(tokens_hash)
12
14
  end
13
15
 
14
- def get_claim(*args)
15
- @decoded_token[0].dig(*args)
16
+ def token_expired?
17
+ expires_at.to_i > 0 && (expires_at <= Time.now.to_i)
16
18
  end
17
19
 
18
- def get_permissions
19
- get_claim("permissions")
20
+ def refresh_token
21
+ new_tokens_hash = KindeSdk.refresh_token(tokens_hash)
22
+ set_hash_related_data(new_tokens_hash)
23
+ @kinde_api_client = KindeSdk.api_client(tokens_hash["access_token"])
24
+ new_tokens_hash
20
25
  end
21
26
 
22
- def get_permission(permission)
23
- {
24
- org_code: get_claim("org_code"),
25
- is_granted: permission_granted?(permission)
26
- }
27
- end
27
+ # token_type is one of: :access_token, :id_token
28
+ #
29
+ # @return [Hash]
30
+ # @example {name: "scp", value: ["openid", "offline"]}
31
+ def get_claim(claim, token_type = :access_token)
32
+ token = tokens_hash[token_type]
33
+ return unless token
34
+
35
+ value = JWT.decode(token, nil, false)[0][claim]
36
+ return unless value
28
37
 
29
- def permission_granted?(permission)
30
- get_claim("permissions").include?(permission)
38
+ { name: claim, value: value }
31
39
  end
32
40
 
33
41
  ::KindeApi.constants.filter { |klass| klass.to_s.end_with?("Api") }.each do |klass|
34
42
  api_klass = Kernel.const_get("KindeApi::#{klass}")
35
43
 
36
- define_method(klass.to_s.downcase.split("api")[0]) { init_instance_api(api_klass) }
44
+ define_method(klass.to_s.gsub(/([a-z\d])([A-Z])/) { "#{$1}_#{$2}" }.downcase.split("_api")[0]) do
45
+ init_instance_api(api_klass)
46
+ end
37
47
  end
38
48
 
39
49
  private
40
50
 
51
+ def set_hash_related_data(tokens_hash)
52
+ @tokens_hash = tokens_hash.transform_keys(&:to_sym)
53
+ @bearer_token = @tokens_hash[:access_token]
54
+ @expires_at = @tokens_hash[:expires_at]
55
+ end
56
+
57
+ # going from another side: prepending each api_client's public method to check token for expiration
41
58
  def init_instance_api(api_klass)
42
- api_klass.new(kinde_api_client)
59
+ instance = api_klass.new(kinde_api_client)
60
+ main_client = self
61
+ methods_to_prepend = instance.public_methods(false).reject { |m| m.to_s.start_with?("api_client") }
62
+ methods_to_prepend.each do |method_name|
63
+ original = instance.method(method_name)
64
+ instance.define_singleton_method(method_name) do |*args, &block|
65
+ main_client.refresh_token if main_client.auto_refresh_tokens && main_client.token_expired?
66
+ original.call(*args, &block)
67
+ end
68
+ end
69
+ instance
43
70
  end
44
71
  end
45
72
  end
@@ -14,7 +14,7 @@ module KindeSdk
14
14
  attr_accessor :debugging
15
15
  attr_accessor :oauth_client
16
16
  attr_accessor :pkce_enabled
17
- attr_accessor :business_name
17
+ attr_accessor :auto_refresh_tokens
18
18
 
19
19
  def initialize
20
20
  @authorize_url = '/oauth2/auth'
@@ -23,7 +23,7 @@ module KindeSdk
23
23
  @logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
24
24
  @scope = 'openid offline email profile'
25
25
  @pkce_enabled = true
26
- @business_name = nil
26
+ @auto_refresh_tokens = true
27
27
 
28
28
  yield(self) if block_given?
29
29
  end
@@ -1,3 +1,3 @@
1
1
  module KindeSdk
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.1"
3
3
  end
data/lib/kinde_sdk.rb CHANGED
@@ -1,11 +1,14 @@
1
1
  require "kinde_sdk/version"
2
2
  require "kinde_sdk/configuration"
3
+ require "kinde_sdk/client/feature_flags"
4
+ require "kinde_sdk/client/permissions"
3
5
  require "kinde_sdk/client"
4
6
 
5
7
  require 'securerandom'
6
8
  require 'oauth2'
7
9
  require 'pkce_challenge'
8
10
  require 'faraday/follow_redirects'
11
+ require 'uri'
9
12
 
10
13
  module KindeSdk
11
14
  class << self
@@ -24,9 +27,9 @@ module KindeSdk
24
27
  # receive url for authorization in Kinde itself
25
28
  #
26
29
  # @return [Hash]
27
- def auth_url(**kwargs)
30
+ def auth_url(redirect_uri: @config.callback_url, **kwargs)
28
31
  params = {
29
- redirect_uri: @config.callback_url,
32
+ redirect_uri: redirect_uri,
30
33
  state: SecureRandom.hex,
31
34
  scope: @config.scope
32
35
  }.merge(**kwargs)
@@ -43,17 +46,28 @@ module KindeSdk
43
46
  # when callback processor receives code, it needs to be used for fetching bearer token
44
47
  #
45
48
  # @return [Hash]
46
- def fetch_tokens(params_or_code, code_verifier = nil)
49
+ def fetch_tokens(params_or_code, code_verifier: nil, redirect_uri: @config.callback_url)
47
50
  code = params_or_code.kind_of?(Hash) ? params.fetch("code") : params_or_code
48
- params = { redirect_uri: @config.callback_url }
51
+ params = {
52
+ redirect_uri: redirect_uri,
53
+ headers: { 'User-Agent' => "Kinde-SDK: Ruby/#{KindeSdk::VERSION}" }
54
+ }
49
55
  params[:code_verifier] = code_verifier if code_verifier
50
56
  @config.oauth_client.auth_code.get_token(code.to_s, params).to_hash
51
57
  end
52
58
 
59
+ # tokens_hash #=>
60
+ # {"access_token"=>"eyJhbGciOiJSUzI1NiIsIm...",
61
+ # "expires_in"=>86399,
62
+ # "id_token"=>"eyJhbGciOiJSUz",
63
+ # "refresh_token"=>"eyJhbGciOiJSUz",
64
+ # "scope"=>"openid offline email profile",
65
+ # "token_type"=>"bearer"}
66
+ #
53
67
  # @return [KindeSdk::Client]
54
- def client(bearer_token)
55
- sdk_api_client = api_client(bearer_token)
56
- KindeSdk::Client.new(sdk_api_client, bearer_token)
68
+ def client(tokens_hash)
69
+ sdk_api_client = api_client(tokens_hash["access_token"])
70
+ KindeSdk::Client.new(sdk_api_client, tokens_hash, @config.auto_refresh_tokens)
57
71
  end
58
72
 
59
73
  def logout_url
@@ -94,10 +108,10 @@ module KindeSdk
94
108
  config = KindeApi::Configuration.default
95
109
  config.configure do |c|
96
110
  c.access_token = bearer_token
97
- c.server_variables = { businessName: business_name }
98
111
  c.host = @config.domain
99
112
  c.debugging = @config.debugging
100
113
  c.logger = @config.logger
114
+ c.scheme = url_scheme(c.scheme)
101
115
  end
102
116
 
103
117
  KindeApi::ApiClient.new(config)
@@ -105,10 +119,11 @@ module KindeSdk
105
119
 
106
120
  private
107
121
 
108
- def business_name
109
- # from https://example.kinde.com fetches `example`
110
- # from https://example-chamois.au.kinde.com fetches `example-chamois.au`
111
- @config.business_name || @config.domain.split("//")[1].split(".")[0..-3].join(".")
122
+ def url_scheme(default_scheme)
123
+ parsed_url = URI.parse(@config.domain.to_s)
124
+ parsed_url.scheme || default_scheme
125
+ rescue URI::InvalidURIError
126
+ default_scheme
112
127
  end
113
128
  end
114
129
  end
@@ -6,6 +6,7 @@ describe KindeSdk do
6
6
  let(:client_secret) { "client_secret" }
7
7
  let(:callback_url) { "http://localhost:3000/callback" }
8
8
  let(:logout_url) { "http://localhost/logout-callback" }
9
+ let(:auto_refresh_tokens) { true }
9
10
 
10
11
  before do
11
12
  KindeSdk.configure do |c|
@@ -14,6 +15,7 @@ describe KindeSdk do
14
15
  c.client_secret = client_secret
15
16
  c.callback_url = callback_url
16
17
  c.logout_url = logout_url
18
+ c.auto_refresh_tokens = auto_refresh_tokens
17
19
  end
18
20
  end
19
21
 
@@ -22,6 +24,12 @@ describe KindeSdk do
22
24
  auth_obj = described_class.auth_url
23
25
  expect(auth_obj[:code_verifier]).not_to be_nil
24
26
  expect(auth_obj[:url]).to start_with("#{domain}/oauth2/auth?client_id=#{client_id}&")
27
+ expect(auth_obj[:url]).to match(/localhost%3A3000%2Fcallback/)
28
+ end
29
+
30
+ it "allows override callback url" do
31
+ auth_obj = described_class.auth_url(redirect_uri: "localhost:5000/another_callback")
32
+ expect(auth_obj[:url]).to match(/localhost%3A5000%2Fanother_callback/)
25
33
  end
26
34
  end
27
35
 
@@ -41,7 +49,46 @@ describe KindeSdk do
41
49
 
42
50
  describe "#api_client" do
43
51
  it "returns initialized api_client instance of KindeApi" do
44
- expect(described_class.api_client("bearer-token")).to be_instance_of(KindeApi::ApiClient)
52
+ expect(described_class.api_client({ "access_token": "bearer-token" }))
53
+ .to be_instance_of(KindeApi::ApiClient)
54
+ end
55
+ end
56
+
57
+ describe "#fetch_tokens" do
58
+ let(:code) { "some-code" }
59
+ before do
60
+ stub_request(:post, "#{domain}/oauth2/token")
61
+ .with(
62
+ body: {
63
+ "code" => code,
64
+ "grant_type" => "authorization_code",
65
+ "redirect_uri" => callback_url
66
+ },
67
+ headers: {
68
+ 'Accept' => '*/*',
69
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
70
+ 'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=',
71
+ 'Content-Type' => 'application/x-www-form-urlencoded',
72
+ 'User-Agent' => "Kinde-SDK: Ruby/#{KindeSdk::VERSION}"
73
+ }
74
+ )
75
+ .to_return(
76
+ status: 200,
77
+ body: { "access_token": "eyJ", "expires_in": 86399, "scope": "", "token_type": "bearer" }.to_json,
78
+ headers: { "content-type" => "application/json;charset=UTF-8" }
79
+ )
80
+ end
81
+
82
+ it "calls /token url with proper body and headers" do
83
+ expect(described_class.fetch_tokens(code).keys).to eq(%w[scope token_type access_token refresh_token expires_at])
84
+ end
85
+
86
+ context "with redefined callback_url" do
87
+ let(:callback_url) { "another-callback" }
88
+
89
+ it "calls /token url with proper body and headers" do
90
+ expect(described_class.fetch_tokens(code).keys.size).to eq(5)
91
+ end
45
92
  end
46
93
  end
47
94
 
@@ -77,7 +124,11 @@ describe KindeSdk do
77
124
  { "aud" => [],
78
125
  "azp" => "19ebb687cd2f405c9f2daf645a8db895",
79
126
  "exp" => 1679600554,
80
- "feature_flags" => nil,
127
+ "feature_flags" => {
128
+ "asd" => { "t" => "b", "v" => true },
129
+ "eeeeee" => { "t" => "i", "v" => 111 },
130
+ "qqq" => { "t" => "s", "v" => "aa" }
131
+ },
81
132
  "iat" => 1679514154,
82
133
  "iss" => "https://example.kinde.com",
83
134
  "jti" => "22c48b2c-da46-4661-a7ff-425c23eceab5",
@@ -87,10 +138,73 @@ describe KindeSdk do
87
138
  "sub" => "kp:b17adf719f7d4b87b611d1a88a09fd15" }
88
139
  end
89
140
  let(:token) { JWT.encode(hash_to_encode, nil, "none") }
90
- let(:client) { described_class.client(token) }
141
+ let(:expires_at) { Time.now.to_i + 10000000 }
142
+ let(:client) { described_class.client({ "access_token": token, "expires_at": expires_at }) }
143
+
144
+ context "with feature flags" do
145
+ it "returns existing flags", :aggregate_failures do
146
+ expect(client.get_flag("asd")).to eq({ code: "asd", is_default: false, type: "boolean", value: true })
147
+ expect(client.get_flag("eeeeee")).to eq({ code: "eeeeee", is_default: false, type: "integer", value: 111 })
148
+ expect(client.get_flag("qqq")).to eq({ code: "qqq", is_default: false, type: "string", value: "aa" })
149
+
150
+ expect { client.get_flag("undefined") }
151
+ .to raise_error(StandardError, "This flag was not found, and no default value has been provided")
152
+ end
153
+
154
+ it "returns fallbacks if no flag present", :aggregate_failures do
155
+ expect(client.get_flag("undefined", { default_value: true }))
156
+ .to eq({ code: "undefined", is_default: true, value: true })
157
+
158
+ expect(client.get_flag("undefined", { default_value: true }, "b")[:value]).to eq(true)
159
+ expect(client.get_flag("undefined", { default_value: "true" }, "s")[:value]).to eq("true")
160
+ expect(client.get_flag("undefined", { default_value: 111 }, "i")[:value]).to eq(111)
161
+ end
162
+
163
+ it "raises argument error when no value type match", :aggregate_failures do
164
+ expect { client.get_flag("undefined", { default_value: true }, "s") }
165
+ .to raise_error(ArgumentError, "Flag undefined value type is different from requested type")
166
+
167
+ expect { client.get_flag("undefined", { default_value: true }, "i") }
168
+ .to raise_error(ArgumentError, "Flag undefined value type is different from requested type")
169
+
170
+ expect { client.get_flag("undefined", { default_value: "true" }, "b") }
171
+ .to raise_error(ArgumentError, "Flag undefined value type is different from requested type")
172
+ end
173
+
174
+ it "behaves the same way for boolean flag wrapper getter", :aggregate_failures do
175
+ expect { client.get_boolean_flag("eeeeee") }
176
+ .to raise_error(ArgumentError, "Flag eeeeee value type is different from requested type")
177
+ expect(client.get_boolean_flag("asd")).to eq(true)
178
+ expect(client.get_boolean_flag("undefined", false)).to eq(false)
179
+
180
+ expect { client.get_boolean_flag("undefined", "true") }
181
+ .to raise_error(ArgumentError, "Flag undefined value type is different from requested type")
182
+ end
183
+
184
+ it "behaves the same way for integer flag wrapper getter", :aggregate_failures do
185
+ expect { client.get_integer_flag("asd") }
186
+ .to raise_error(ArgumentError, "Flag asd value type is different from requested type")
187
+ expect(client.get_integer_flag("eeeeee")).to eq(111)
188
+ expect(client.get_integer_flag("undefined", 111)).to eq(111)
189
+
190
+ expect { client.get_integer_flag("undefined", "true") }
191
+ .to raise_error(ArgumentError, "Flag undefined value type is different from requested type")
192
+ end
193
+
194
+ it "behaves the same way for string flag wrapper getter", :aggregate_failures do
195
+ expect { client.get_string_flag("asd") }
196
+ .to raise_error(ArgumentError, "Flag asd value type is different from requested type")
197
+ expect(client.get_string_flag("qqq")).to eq("aa")
198
+ expect(client.get_string_flag("undefined", "111")).to eq("111")
199
+
200
+ expect { client.get_string_flag("undefined", true) }
201
+ .to raise_error(ArgumentError, "Flag undefined value type is different from requested type")
202
+ end
203
+ end
91
204
 
92
205
  it "returns requested claim from bearer", :aggregate_failures do
93
- expect(client.get_claim("scp")).to eq(hash_to_encode["scp"])
206
+ expect(client.get_claim("scp")).to eq({ name: "scp", value: hash_to_encode["scp"] })
207
+ expect(client.get_claim("scp", :id_token)).to be_nil
94
208
  expect(client.get_claim("aaa")).to be_nil
95
209
  end
96
210
 
@@ -104,8 +218,23 @@ describe KindeSdk do
104
218
  expect(client.permission_granted?("asd")).to be(false)
105
219
  end
106
220
 
221
+ context "with expiration check" do
222
+ it { expect(client.token_expired?).to be(false) }
223
+
224
+ context "when token expired" do
225
+ let(:expires_at) { Time.now.to_i - 1 }
226
+
227
+ it { expect(client.token_expired?).to be(true) }
228
+ end
229
+ end
230
+
107
231
  describe "api instances" do
108
- it 'initializes client by passing the bearer' do
232
+ before do
233
+ stub_request(:get, "#{domain}/oauth2/user_profile")
234
+ # allow(client.oauth).to receive(:get_user_with_http_info).and_return(["data", 200, {}])
235
+ end
236
+
237
+ it 'initializes client by passing the tokens_hash' do
109
238
  expect(client).to be_instance_of(KindeSdk::Client)
110
239
  end
111
240
 
@@ -116,6 +245,33 @@ describe KindeSdk do
116
245
  it "initializes users instance api" do
117
246
  expect(client.users).to be_instance_of(KindeApi::UsersApi)
118
247
  end
248
+
249
+ it "initializes feature flags instance api" do
250
+ expect(client.feature_flags).to be_instance_of(KindeApi::FeatureFlagsApi)
251
+ end
252
+
253
+ it "does not call for refresh tokens" do
254
+ expect(client).not_to receive(:refresh_token)
255
+ client.oauth.get_user({})
256
+ end
257
+
258
+ context "when token expired" do
259
+ let(:expires_at) { Time.now.to_i - 1 }
260
+
261
+ it "calls refresh_tokens before method if token expired" do
262
+ expect(client).to receive(:refresh_token).at_least(:once)
263
+ client.oauth.get_user({})
264
+ end
265
+
266
+ context "when auto_refresh_tokens disabled" do
267
+ let(:auto_refresh_tokens) { false }
268
+
269
+ it "does not call for refresh tokens" do
270
+ expect(client).not_to receive(:refresh_token)
271
+ client.oauth.get_user({})
272
+ end
273
+ end
274
+ end
119
275
  end
120
276
  end
121
277
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require "kinde_sdk"
2
2
  require "webmock/rspec"
3
3
 
4
+ WebMock.disable_net_connect!
5
+
4
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
5
7
  RSpec.configure do |config|
6
8
  # rspec-expectations config goes here. You can use an alternate