Class: Clerk::SDK

Inherits:
OpenAPIClient show all
Defined in:
lib/clerk/sdk.rb

Constant Summary collapse

JWKS_CACHE_LIFETIME =

How often (in seconds) should JWKs be refreshed

3600
@@jwks_cache =

rubocop:disable Style/ClassVars

JWKSCache.new(JWKS_CACHE_LIFETIME)

Instance Attribute Summary

Attributes inherited from OpenAPIClient

#actor_tokens, #allowlist_identifiers, #api_keys, #beta_features, #billing, #blocklist_identifiers, #clients, #domains, #email_addresses, #email_and_sms_templates, #email_sms_templates, #instance_settings, #invitations, #jwks, #jwt_templates, #m2m, #machines, #miscellaneous, #oauth_access_tokens, #oauth_applications, #organization_domains, #organization_invitations, #organization_memberships, #organization_permissions, #organization_roles, #organizations, #phone_numbers, #proxy_checks, #redirect_urls, #role_sets, #saml_connections, #sessions, #sign_in_tokens, #sign_ups, #templates, #testing_tokens, #users, #waitlist_entries, #webhooks

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from OpenAPIClient

#get_url, #init_sdks

Constructor Details

#initialize(client: nil, retry_config: nil, timeout_ms: nil, secret_key: nil, security_source: nil, server_idx: nil, server_url: nil, url_params: nil) ⇒ SDK

Returns a new instance of SDK.



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/clerk/sdk.rb', line 27

def initialize(client: nil, retry_config: nil, timeout_ms: nil, secret_key: nil, security_source: nil, server_idx: nil, server_url: nil, url_params: nil)
  secret_key ||= Clerk.configuration.secret_key
  super(
    client: client,
    retry_config: retry_config,
    timeout_ms: timeout_ms,
    bearer_auth: secret_key,
    security_source: security_source,
    server_idx: server_idx,
    server_url: server_url,
    url_params: url_params
  )
end

Class Method Details

.jwks_cacheObject

rubocop:enable Style/ClassVars



23
24
25
# File 'lib/clerk/sdk.rb', line 23

def self.jwks_cache
  @@jwks_cache
end

Instance Method Details

#decode_token(token) ⇒ Object

Returns the decoded JWT payload without verifying if the signature is valid.

WARNING: This will not verify whether the signature is valid. You should not use this for untrusted messages! You most likely want to use ‘verify_token`.



45
46
47
# File 'lib/clerk/sdk.rb', line 45

def decode_token(token)
  JWT.decode(token, nil, false).first
end

#verify_token(token, force_refresh_jwks: false, algorithms: ['RS256'], timeout: 5) ⇒ Object

Decode the JWT and verify it’s valid (verify claims, signature etc.) using the provided algorithms.

JWKS are cached for JWKS_CACHE_LIFETIME seconds, in order to avoid unecessary roundtrips. In order to invalidate the cache, pass ‘force_refresh_jwks: true`.

A timeout for the request to the JWKs endpoint can be set with the ‘timeout` argument.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/clerk/sdk.rb', line 55

def verify_token(token, force_refresh_jwks: false, algorithms: ['RS256'], timeout: 5)
  jwk_loader = lambda do |options|
    # JWT.decode requires that the 'keys' key in the Hash is a symbol (as
    # opposed to a string which our SDK returns by default)
    {keys: SDK.jwks_cache.fetch(self, kid_not_found: options[:invalidate] || options[:kid_not_found], force_refresh: force_refresh_jwks)}
  end

  begin
    claims = JWT.decode(token, nil, true, algorithms: algorithms, exp_leeway: timeout, jwks: jwk_loader).first
  rescue JWT::ExpiredSignature => e
    raise e
  rescue JWT::InvalidIatError => e
    raise e
  rescue JWT::DecodeError => e
    raise e
  rescue StandardError => e
    raise e
  end

  # orgs
  if claims['v'].nil? || claims['v'] == 1
    claims['v'] = 1
  elsif claims['v'] == 2 && claims['o']
    claims['org_id']          = claims['o'].fetch('id', nil)
    claims['org_slug']        = claims['o'].fetch('slg', nil)
    claims['org_role']        = "org:#{claims['o'].fetch('rol', nil)}"

    org_permissions = compute_org_permissions_from_v2_token(claims)
    claims['org_permissions'] = org_permissions if org_permissions.any?
    claims.delete('o')
    claims.delete('fea')
  end

  claims
end