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, #agent_tasks, #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