Class: KindeSdk::Client

Inherits:
Object
  • Object
show all
Includes:
Entitlements, FeatureFlags, Permissions, Roles, Logging
Defined in:
lib/kinde_sdk/client.rb,
lib/kinde_sdk/client/roles.rb,
lib/kinde_sdk/client/permissions.rb,
lib/kinde_sdk/client/entitlements.rb,
lib/kinde_sdk/client/feature_flags.rb

Defined Under Namespace

Modules: Entitlements, FeatureFlags, Permissions, Roles

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Entitlements

#get_entitlements, #has_billing_entitlements?, #has_entitlements?

Methods included from Logging

#log_debug, #log_error, #log_info, #log_warning, resolve_logger, write_log

Methods included from Roles

#getRoles, #get_roles, #has_roles?

Methods included from Permissions

#getAllPermissions, #getPermissions, #get_permission, #get_permissions, #get_permissions_legacy, #permission_granted?

Methods included from FeatureFlags

#getFlags, #get_boolean_flag, #get_flag, #get_flags, #get_integer_flag, #get_string_flag, #has_feature_flags?

Constructor Details

#initialize(sdk_api_client, tokens_hash, auto_refresh_tokens, force_api = false) ⇒ Client

Returns a new instance of Client.



32
33
34
35
36
37
38
39
40
# File 'lib/kinde_sdk/client.rb', line 32

def initialize(sdk_api_client, tokens_hash, auto_refresh_tokens, force_api = false)
  @kinde_api_client = sdk_api_client
  @auto_refresh_tokens = auto_refresh_tokens
  @token_store = TokenManager.create_store(tokens_hash)
  @force_api = force_api

  # refresh the token if it's expired and auto_refresh_tokens is enabled
  refresh_token if auto_refresh_tokens && TokenManager.token_expired?(@token_store)
end

Instance Attribute Details

#auto_refresh_tokensObject

Returns the value of attribute auto_refresh_tokens.



30
31
32
# File 'lib/kinde_sdk/client.rb', line 30

def auto_refresh_tokens
  @auto_refresh_tokens
end

#force_apiObject

Returns the value of attribute force_api.



30
31
32
# File 'lib/kinde_sdk/client.rb', line 30

def force_api
  @force_api
end

#kinde_api_clientObject

Returns the value of attribute kinde_api_client.



30
31
32
# File 'lib/kinde_sdk/client.rb', line 30

def kinde_api_client
  @kinde_api_client
end

#token_storeObject

Returns the value of attribute token_store.



30
31
32
# File 'lib/kinde_sdk/client.rb', line 30

def token_store
  @token_store
end

Instance Method Details

#bearer_tokenString

Returns the bearer token for backwards compatibility

Returns:

  • (String)


44
45
46
# File 'lib/kinde_sdk/client.rb', line 44

def bearer_token
  @token_store.bearer_token
end

#enhanced_user_profileOpenStruct

Get enhanced user profile information.

Returns:

  • (OpenStruct)

    Enhanced user profile data

Raises:



359
360
361
362
363
364
# File 'lib/kinde_sdk/client.rb', line 359

def 
  frontend.
rescue StandardError => e
  log_error("Failed to fetch enhanced profile: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch enhanced profile: #{e.message}"
end

#entitlement(key) ⇒ OpenStruct?

Get a specific entitlement by key.

Parameters:

  • key (String)

    The entitlement key to retrieve

Returns:

  • (OpenStruct, nil)

    The entitlement response or nil if not found

Raises:



207
208
209
210
211
212
# File 'lib/kinde_sdk/client.rb', line 207

def entitlement(key)
  frontend.get_entitlement(key)
rescue StandardError => e
  log_error("Failed to fetch entitlement for #{key}: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch entitlement: #{e.message}"
end

#entitlements(page_size: 10, starting_after: nil) ⇒ OpenStruct

Get entitlements for the authenticated user with pagination support.

Parameters:

  • page_size (Integer) (defaults to: 10)

    Number of results per page (default: 10)

  • starting_after (String) (defaults to: nil)

    The ID to start after for pagination

Returns:

  • (OpenStruct)

    Response containing entitlements data

Raises:



177
178
179
180
181
182
# File 'lib/kinde_sdk/client.rb', line 177

def entitlements(page_size: 10, starting_after: nil)
  frontend.get_entitlements(page_size: page_size, starting_after: starting_after)
rescue StandardError => e
  log_error("Failed to fetch entitlements: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch entitlements: #{e.message}"
end

#expires_atInteger

Returns the token expiration time for backwards compatibility

Returns:

  • (Integer)


56
57
58
# File 'lib/kinde_sdk/client.rb', line 56

def expires_at
  @token_store.expires_at
end

#frontendObject

Frontend API access - Internal use only Uses user access tokens instead of M2M tokens



165
166
167
# File 'lib/kinde_sdk/client.rb', line 165

def frontend
  @frontend_client ||= KindeSdk::Internal::FrontendClient.new(@token_store, KindeSdk.config.domain)
end

#generate_portal_url(domain:, return_url:, sub_nav: PortalPage::PROFILE) ⇒ Hash

Generate a URL to the user profile portal

Parameters:

  • domain (String)

    The domain of the Kinde instance

  • return_url (String)

    URL to redirect to after completing the profile flow

  • sub_nav (String) (defaults to: PortalPage::PROFILE)

    Sub-navigation section to display

Returns:

  • (Hash)

    A hash containing the generated URL

Raises:

  • (StandardError)

    If the request fails or returns invalid data



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/kinde_sdk/client.rb', line 96

def generate_portal_url(domain:, return_url:, sub_nav: PortalPage::PROFILE)
  refresh_token if auto_refresh_tokens && token_expired?

  unless return_url.start_with?('http')
    raise StandardError, 'generatePortalUrl: returnUrl must be an absolute URL'
  end

  params = {
    'return_url' => return_url,
    'sub_nav' => sub_nav
  }

  response = Faraday.get("#{domain}/account_api/v1/portal_link", params) do |req|
    req.headers['Authorization'] = "Bearer #{@token_store.bearer_token}"
  end

  unless response.success?
    raise StandardError, "Failed to fetch profile URL: #{response.status} #{response.reason_phrase}"
  end

  result = JSON.parse(response.body)
  unless result['url'].is_a?(String)
    raise StandardError, "Invalid URL received from API"
  end

  begin
    { url: URI.parse(result['url']) }
  rescue URI::InvalidURIError => e
    log_error(e.message)
    raise StandardError, "Invalid URL format received from API: #{result['url']}"
  end
end

#generatePortalUrl(return_url, sub_nav = PortalPage::PROFILE) ⇒ Hash

PHP SDK compatible portal URL generation method.

Parameters:

  • return_url (String)

    URL to redirect to after completing the profile flow

  • sub_nav (String) (defaults to: PortalPage::PROFILE)

    Sub-navigation section to display (defaults to 'profile')

Returns:

  • (Hash)

    A hash containing the generated URL

Raises:

  • (KindeSdk::APIError)

    If the user is not authenticated or API request fails

  • (ArgumentError)

    If the return_url is not an absolute URL



340
341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/kinde_sdk/client.rb', line 340

def generatePortalUrl(return_url, sub_nav = PortalPage::PROFILE)
  unless token_store.bearer_token
    raise KindeSdk::APIError, 'generatePortalUrl: Access Token not found'
  end

  unless return_url.start_with?('http')
    raise ArgumentError, 'generatePortalUrl: returnUrl must be an absolute URL'
  end

  frontend.get_portal_link(subnav: sub_nav, return_url: return_url)
rescue StandardError => e
  log_error("Failed to generate portal URL: #{e.message}")
  raise KindeSdk::APIError, "Unable to generate portal URL: #{e.message}"
end

#get_claim(claim, token_type = :access_token) ⇒ Hash

token_type is one of: :access_token, :id_token

Examples:

"scp", value: ["openid", "offline"]

Returns:

  • (Hash)


77
78
79
80
81
82
83
84
85
86
87
# File 'lib/kinde_sdk/client.rb', line 77

def get_claim(claim, token_type = :access_token)
  refresh_token if auto_refresh_tokens && token_expired?

  token = @token_store.tokens[token_type.to_sym]
  return unless token

  value = JWT.decode(token, nil, false)[0][claim]
  return unless value

  { name: claim, value: value }
end

#getAllEntitlementsArray Also known as: all_entitlements

Get all entitlements for the authenticated user, handling pagination automatically.

Returns:

  • (Array)

    All entitlements

Raises:



188
189
190
191
192
193
194
195
196
197
# File 'lib/kinde_sdk/client.rb', line 188

def getAllEntitlements
  unless token_store.bearer_token
    raise KindeSdk::APIError, 'User must be authenticated to get entitlements'
  end

  paginate_all_results('entitlements') { |starting_after| entitlements(page_size: 100, starting_after: starting_after) }
rescue StandardError => e
  log_error("Failed to fetch all entitlements: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch all entitlements: #{e.message}"
end

#getEntitlement(key) ⇒ OpenStruct?

PHP SDK compatible alias for entitlement

Parameters:

  • key (String)

    The entitlement key to retrieve

Returns:

  • (OpenStruct, nil)

    The entitlement response or nil if not found

Raises:



219
220
221
222
223
224
225
226
227
# File 'lib/kinde_sdk/client.rb', line 219

def getEntitlement(key)
  # Find the specific entitlement from all entitlements (like PHP SDK does)
  entitlements = getAllEntitlements
  
  entitlements.find { |entitlement| entitlement.feature_key == key }
rescue StandardError => e
  log_error("Failed to get entitlement for #{key}: #{e.message}")
  raise KindeSdk::APIError, "Unable to get entitlement: #{e.message}"
end

#getEntitlementLimit(key) ⇒ Integer? Also known as: entitlement_limit

Get the maximum limit for a specific entitlement.

Parameters:

  • key (String)

    The entitlement key

Returns:

  • (Integer, nil)

    The maximum limit or nil if not found

Raises:



257
258
259
260
261
262
263
# File 'lib/kinde_sdk/client.rb', line 257

def getEntitlementLimit(key)
  entitlement = getEntitlement(key)
  entitlement ? entitlement.entitlement_limit_max : nil
rescue StandardError => e
  log_error("Error getting entitlement limit for #{key}: #{e.message}")
  nil
end

#has_entitlement?(feature_key) ⇒ Boolean

Check if the user has a specific entitlement.

Parameters:

  • feature_key (String)

    The entitlement key to check

Returns:

  • (Boolean)

    True if the user has the entitlement, false otherwise



233
234
235
236
237
238
239
# File 'lib/kinde_sdk/client.rb', line 233

def has_entitlement?(feature_key)
  entitlement_response = entitlement(feature_key)
  !entitlement_response&.data&.entitlement.nil?
rescue StandardError => e
  log_error("Error checking entitlement for #{feature_key}: #{e.message}")
  false
end

#hasEntitlement(key) ⇒ Boolean

PHP SDK compatible alias for has_entitlement?

Parameters:

  • key (String)

    The entitlement key to check

Returns:

  • (Boolean)

    True if the user has the entitlement, false otherwise



245
246
247
248
249
250
# File 'lib/kinde_sdk/client.rb', line 245

def hasEntitlement(key)
  getEntitlement(key) != nil
rescue StandardError => e
  log_error("Error checking entitlement for #{key}: #{e.message}")
  false
end

#oauthObject

Custom oauth method that provides backward compatibility



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/kinde_sdk/client.rb', line 138

def oauth
  oauth_api = init_instance_api(KindeApi::OAuthApi)
  
  # Add backward compatibility for get_user method
  unless oauth_api.respond_to?(:get_user)
    oauth_api.define_singleton_method(:get_user) do |opts = {}|
      # Call the new method
       = (opts)
      
      # Convert UserProfileV2 to UserProfile format as a hash
      # This provides backward compatibility without depending on the UserProfile class
      {
        id: .id || .sub,
        preferred_email: .email,
        provided_id: .provided_id,
        last_name: .family_name,
        first_name: .given_name,
        picture: .picture
      }
    end
  end
  
  oauth_api
end

Generate a URL to the user profile portal.

Parameters:

  • return_url (String)

    URL to redirect to after completing the profile flow

  • sub_nav (String)

    Sub-navigation section to display (defaults to 'profile')

Returns:

  • (Hash)

    A hash containing the generated URL

Raises:



326
327
328
329
330
331
# File 'lib/kinde_sdk/client.rb', line 326

def portal_link(return_url:, page: PortalPage::PROFILE)
  frontend.get_portal_link(subnav: page, return_url: return_url)
rescue StandardError => e
  log_error("Failed to get portal link: #{e.message}")
  raise KindeSdk::APIError, "Unable to get portal link: #{e.message}"
end

#refresh_tokenObject



64
65
66
67
68
69
70
71
# File 'lib/kinde_sdk/client.rb', line 64

def refresh_token
  new_tokens_hash = TokenManager.refresh_tokens(@token_store, Current.session)
  return nil unless new_tokens_hash

  @token_store.set_tokens(new_tokens_hash)
  @kinde_api_client = KindeSdk.api_client(@token_store.bearer_token)
  new_tokens_hash
end

#token_expired?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/kinde_sdk/client.rb', line 60

def token_expired?
  TokenManager.token_expired?(@token_store)
end

#tokens_hashHash

Returns the tokens hash for backwards compatibility

Returns:

  • (Hash)


50
51
52
# File 'lib/kinde_sdk/client.rb', line 50

def tokens_hash
  @token_store.tokens
end

#user_feature_flags(page_size: 10, starting_after: nil) ⇒ OpenStruct

Get user feature flags with pagination support.

Parameters:

  • page_size (Integer) (defaults to: 10)

    Number of results per page (default: 10)

  • starting_after (String) (defaults to: nil)

    The ID to start after for pagination

Returns:

  • (OpenStruct)

    Response containing feature flags data

Raises:



274
275
276
277
278
279
# File 'lib/kinde_sdk/client.rb', line 274

def user_feature_flags(page_size: 10, starting_after: nil)
  frontend.get_feature_flags(page_size: page_size, starting_after: starting_after)
rescue StandardError => e
  log_error("Failed to fetch feature flags: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch feature flags: #{e.message}"
end

#user_permissions(page_size: 10, starting_after: nil) ⇒ OpenStruct

Get user permissions with pagination support.

Parameters:

  • page_size (Integer) (defaults to: 10)

    Number of results per page (default: 10)

  • starting_after (String) (defaults to: nil)

    The ID to start after for pagination

Returns:

  • (OpenStruct)

    Response containing permissions data

Raises:



287
288
289
290
291
292
# File 'lib/kinde_sdk/client.rb', line 287

def user_permissions(page_size: 10, starting_after: nil)
  frontend.get_user_permissions(page_size: page_size, starting_after: starting_after)
rescue StandardError => e
  log_error("Failed to fetch permissions: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch permissions: #{e.message}"
end

#user_properties(page_size: 10, starting_after: nil) ⇒ OpenStruct

Get user properties with pagination support.

Parameters:

  • page_size (Integer) (defaults to: 10)

    Number of results per page (default: 10)

  • starting_after (String) (defaults to: nil)

    The ID to start after for pagination

Returns:

  • (OpenStruct)

    Response containing properties data

Raises:



300
301
302
303
304
305
# File 'lib/kinde_sdk/client.rb', line 300

def user_properties(page_size: 10, starting_after: nil)
  frontend.get_user_properties(page_size: page_size, starting_after: starting_after)
rescue StandardError => e
  log_error("Failed to fetch properties: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch properties: #{e.message}"
end

#user_roles(page_size: 10, starting_after: nil) ⇒ OpenStruct

Get user roles with pagination support.

Parameters:

  • page_size (Integer) (defaults to: 10)

    Number of results per page (default: 10)

  • starting_after (String) (defaults to: nil)

    The ID to start after for pagination

Returns:

  • (OpenStruct)

    Response containing roles data

Raises:



313
314
315
316
317
318
# File 'lib/kinde_sdk/client.rb', line 313

def user_roles(page_size: 10, starting_after: nil)
  frontend.get_user_roles(page_size: page_size, starting_after: starting_after)
rescue StandardError => e
  log_error("Failed to fetch roles: #{e.message}")
  raise KindeSdk::APIError, "Unable to fetch roles: #{e.message}"
end