clerk-sdk-ruby 1.0.0 → 2.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f285e5ca6280db100eed30796279e412901f157a3fd43d16a41a64d9c0cd85f
4
- data.tar.gz: 32d0fab6c78b57c0f06fa9d3ef077f077cb6533ada6a400f98bec6a087d939e8
3
+ metadata.gz: 1e7b69485de55997a4dac75759908e7709dcb7fdb83c92fe09d2c4748a0a74f7
4
+ data.tar.gz: a0afbe19f7d6a7a9a998e82b798a8a548f051505e14f3b1d50688d2aaa436d7f
5
5
  SHA512:
6
- metadata.gz: 7721083974266f6b18c6ceb1e1a14abc623caad474a7fcf7a065aafa4ac51c11f732f12db257fa46e3f903a4c9985eb0e6c21e451d3ffc877b7f434ba482fe91
7
- data.tar.gz: b6a5689badfc699d7d03accb5a301a3504adf8eae009ef450b462fee9a20f995c2ec255ec9b771175fd76209ba991544a51a9e8cd6f0a14f82d6342a922942fb
6
+ metadata.gz: 062e4297db4b8b20e1a6ed6bf6d69a2b0f2df0f5aecc5d716e6b883877fea484476c9d75bf7e7fda294b88774b707b60fd09a85604f7f9363b1161f622d4947a
7
+ data.tar.gz: 50ecd09031d4383b5d136840f8457841253c86122fb3a4a8769d8d86553fb3d2ff9323f0cb98bdde68f4990d2c4cc955b9996a3fca09a0c597e10a7bbb39d8eb
data/.gitignore CHANGED
@@ -6,3 +6,5 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+
10
+ .byebug_history
data/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ ## unreleased
2
+
3
+ This release (v2) introduces the new networkless middleware which is compatible
4
+ with the new authentication scheme, dubbed *AuthV2*.
5
+
6
+ It is backwards-incompatible with applications using AuthV1.
7
+
8
+ - [BREAKING]: In order to use this version, you must set the authVersion prop
9
+ accordingly in your frontend: `Clerk.load({authVersion: 2})`
10
+
11
+ ## 1.0.3 - 2021-07-21
12
+
13
+ - fix: Proper endpoint for oauth_access_token method
14
+
15
+ ## 1.0.2 - 2021-06-03
16
+
17
+ - fix: Instantiation of `Clerk::SDK` without prior call to `Clerk.configure`
18
+
19
+ ## 1.0.1 - 2021-06-03
20
+
21
+ ### enhancements
22
+
23
+ - Middleware now uses a proxy object which lazy loads the Clerk session and user only when needed
24
+
25
+ ## 1.0.0 - 2021-05-27
26
+
27
+ - initial release
data/Gemfile.lock CHANGED
@@ -1,33 +1,43 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- clerk-sdk-ruby (1.0.0)
4
+ clerk-sdk-ruby (1.0.3)
5
5
  faraday (~> 1.4.1)
6
+ jwt (~> 2.2)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
- faraday (1.4.1)
11
+ byebug (11.1.3)
12
+ faraday (1.4.3)
13
+ faraday-em_http (~> 1.0)
14
+ faraday-em_synchrony (~> 1.0)
11
15
  faraday-excon (~> 1.1)
12
16
  faraday-net_http (~> 1.0)
13
17
  faraday-net_http_persistent (~> 1.1)
14
18
  multipart-post (>= 1.2, < 3)
15
19
  ruby2_keywords (>= 0.0.4)
20
+ faraday-em_http (1.0.0)
21
+ faraday-em_synchrony (1.0.0)
16
22
  faraday-excon (1.1.0)
17
23
  faraday-net_http (1.0.1)
18
- faraday-net_http_persistent (1.1.0)
24
+ faraday-net_http_persistent (1.2.0)
25
+ jwt (2.2.3)
19
26
  minitest (5.14.2)
20
27
  multipart-post (2.1.1)
21
28
  rake (13.0.3)
22
- ruby2_keywords (0.0.4)
29
+ ruby2_keywords (0.0.5)
30
+ timecop (0.9.4)
23
31
 
24
32
  PLATFORMS
25
33
  x86_64-linux
26
34
 
27
35
  DEPENDENCIES
36
+ byebug (~> 11.1)
28
37
  clerk-sdk-ruby!
29
38
  minitest (~> 5.0)
30
39
  rake (~> 13.0)
40
+ timecop (~> 0.9.4)
31
41
 
32
42
  BUNDLED WITH
33
- 2.2.15
43
+ 2.2.24
data/README.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Clerk Ruby SDK
2
2
 
3
+ **NOTE**: This is the v2 branch of the SDK, which requires that you use AuthV2
4
+ in your frontend. This means that you have to set the `authVersion` prop
5
+ accordingly in your frontend:
6
+
7
+ ```javascript
8
+ Clerk.load({authVersion: 2})
9
+ ```
10
+
11
+ ----------
12
+
3
13
  Thank you for choosing [Clerk](https://clerk.dev/) for your authentication,
4
14
  session & user management needs!
5
15
 
@@ -63,10 +73,10 @@ supported configuration settings their environment variable equivalents:
63
73
 
64
74
  ```ruby
65
75
  Clerk.configure do |c|
66
- c.api_key = "your_api_key" # if omitted: ENV.fetch("CLERK_API_KEY") - will fail if unset
76
+ c.api_key = "your_api_key" # if omitted: ENV["CLERK_API_KEY"] - API calls will fail if unset
67
77
  c.base_url = "https://..." # if omitted: "https://api.clerk.dev/v1/"
68
78
  c.logger = Logger.new(STDOUT) # if omitted, no logging
69
- c.middleware_cache_store = ActiveSupport::Cache::FileStore.new("/tmp/clerk_middleware_cache") # if omitted: Rails.cache or no caching (if not in a Rails app)
79
+ c.middleware_cache_store = ActiveSupport::Cache::FileStore.new("/tmp/clerk_middleware_cache") # if omitted: no caching
70
80
  end
71
81
  ```
72
82
 
@@ -94,17 +104,17 @@ for details.
94
104
 
95
105
  ## Rack middleware
96
106
 
97
- The SDK comes with a Rack middleware which sets the Clerk session and user in
98
- the Rack environment. The keys are: `clerk_session` and `clerk_user` for the
99
- session and user respectively. If the API responds with an error `clerk_error`
100
- will be set.
107
+ The SDK comes with a Rack middleware which lazily loads the Clerk session and
108
+ user. It inserts a `clerk` key in the Rack environment, which is an instance
109
+ of `Clerk::Proxy`. To get the session or the user of the session, you call
110
+ `session` or `user` respectively. In case there is no session, you can retrieve
111
+ the API error with the `error` getter method.
101
112
 
102
113
  ## Rails integration
103
114
 
104
115
  The SDK will automatically add the [Rack middleware](#rack-middleware) to the
105
- middleware stack, using `Rails.cache` for its cache. For easier access to the
106
- Clerk session and user, include the `Clerk::Authenticatable` concern in your
107
- controller:
116
+ middleware stack. For easier access to the Clerk session and user, include the
117
+ `Clerk::Authenticatable` concern in your controller:
108
118
 
109
119
  ```ruby
110
120
  require "clerk/authenticatable"
data/bin/console CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "bundler/setup"
5
5
  require "clerk"
6
+ require "byebug"
6
7
 
7
8
  # You can add fixtures and/or initialization code here to make experimenting
8
9
  # with your gem easier. You can also use a different console, if you like.
@@ -28,4 +28,8 @@ Gem::Specification.new do |spec|
28
28
  spec.require_paths = ["lib"]
29
29
 
30
30
  spec.add_dependency "faraday", "~> 1.4.1"
31
+ spec.add_dependency "jwt", '~> 2.2'
32
+
33
+ spec.add_development_dependency "byebug", "~> 11.1"
34
+ spec.add_development_dependency "timecop", "~> 0.9.4"
31
35
  end
@@ -5,16 +5,52 @@ module Clerk
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  protected
8
+
9
+ # Makes a request to the Clerk API to verify the session again and return
10
+ # the Session object. Subsequent calls to this method will return the cached
11
+ # Session object.
12
+ #
13
+ # NOTE: For better performance, you can instead use `#clerk_session_claims`
14
+ # which already contains the verified claims as retrieved from the session
15
+ # token.
8
16
  def clerk_session
9
- request.env["clerk_session"]
17
+ request.env["clerk"].session
18
+ end
19
+
20
+ # Makes a request to the Clerk API to verify the session again. Returns the
21
+ # session object as fetched from the API.
22
+ #
23
+ # NOTE: For better performance, you can instead use `#clerk_session_claims`
24
+ # which already contains the verified claims as retrieved from the session
25
+ # token.
26
+ #
27
+ # See https://docs.clerk.dev/reference/backend-api-reference/sessions#verify-a-session
28
+ def clerk_reverify_session!
29
+ request.env["clerk"].verify_session
30
+ end
31
+
32
+ def clerk_verified_session_claims
33
+ request.env["clerk"].session_claims
10
34
  end
11
35
 
36
+ def clerk_verified_session_token
37
+ request.env["clerk"].session_token
38
+ end
39
+
40
+ # Makes a request to the Clerk API to fetch the data of the authenticated
41
+ # session's user. If caching is configured (see
42
+ # Config.middleware_cache_store), subsequent calls will return the cached
43
+ # object.
12
44
  def clerk_user
13
- request.env["clerk_user"]
45
+ request.env["clerk"].user
46
+ end
47
+
48
+ def clerk_user_id
49
+ request.env["clerk"].user_id
14
50
  end
15
51
 
16
52
  def clerk_user_signed_in?
17
- !!clerk_user
53
+ !!clerk_verified_session_claims
18
54
  end
19
55
 
20
56
  def clerk_sign_in_url
@@ -30,8 +66,10 @@ module Clerk
30
66
  end
31
67
 
32
68
  included do
33
- helper_method :clerk_session, :clerk_user, :clerk_user_signed_in?,
34
- :clerk_sign_in_url, :clerk_sign_up_url, :clerk_user_profile_url
69
+ helper_method :clerk_session, :clerk_reverify_session!,
70
+ :clerk_verified_session_claims, :clerk_verified_session_token,
71
+ :clerk_user, :clerk_user_id, :clerk_user_signed_in?, :clerk_sign_in_url,
72
+ :clerk_sign_up_url, :clerk_user_profile_url
35
73
  end
36
74
  end
37
75
  end
File without changes
@@ -8,48 +8,75 @@ module Clerk
8
8
 
9
9
  def call(env)
10
10
  req = Rack::Request.new(env)
11
- token = req.cookies["__session"]
11
+ env["clerk"] = Proxy.new(env)
12
+ @app.call(env)
13
+ end
14
+ end
12
15
 
13
- if token
14
- sess_id = req.params["_clerk_session_id"]
15
- begin
16
- env["clerk_session"] = fetch_session(token, sess_id)
17
- rescue Errors::Authentication => e
18
- env["clerk_error"] = e
19
- end
20
- end
21
- if sess = env["clerk_session"]
22
- env["clerk_user"] = fetch_user(sess["user_id"])
16
+ class Proxy
17
+ attr_reader :session_id, :error
18
+ def initialize(env)
19
+ req = Rack::Request.new(env)
20
+ @token = req.cookies["__session"]
21
+ @session_id = req.params["_clerk_session_id"]
22
+ @session = nil
23
+ @user_id = nil
24
+ @user = nil
25
+ end
26
+
27
+ def session
28
+ return nil if @token.nil?
29
+ return @session if @session
30
+
31
+ begin
32
+ @session = fetch_session
33
+ rescue Errors::Authentication => e
34
+ @error = e
23
35
  end
24
- @app.call(env)
36
+ @session
37
+ end
38
+
39
+ def user_id
40
+ @user_id ||= session.dig("user_id")
41
+ end
42
+
43
+ def user
44
+ return nil if session.nil?
45
+ @user ||= fetch_user(user_id)
46
+ end
47
+
48
+ def debug
49
+ (instance_variables - [:@sdk]).map do |ivar|
50
+ [ivar.to_s, instance_variable_get(ivar)]
51
+ end.to_h
25
52
  end
26
53
 
27
54
  private
28
- def clerk_sdk
29
- SDK.new
55
+ def sdk
56
+ @sdk ||= SDK.new
57
+ end
58
+
59
+ def cache_key
60
+ @cache_key ||= @token.split(".")[1]
30
61
  end
31
62
 
32
- def fetch_session(token, sess_id)
33
- cache_key = token.split(".")[1]
34
- if sess_id
35
- session = cached_fetch("clerk_session:#{sess_id}:#{cache_key}") do
36
- sdk = clerk_sdk
37
- sdk.sessions.verify_token(sess_id, token)
63
+ def fetch_session
64
+ if session_id
65
+ cached_fetch("clerk_session:#{session_id}:#{cache_key}") do
66
+ sdk.sessions.verify_token(session_id, @token)
38
67
  end
39
68
  else
40
- session = cached_fetch("clerk_session:#{cache_key}") do
41
- sdk = clerk_sdk
42
- client = sdk.clients.verify_token(token)
43
- sess_id = client["last_active_session_id"]
69
+ cached_fetch("clerk_session:#{cache_key}") do
70
+ client = sdk.clients.verify_token(@token)
71
+ @session_id = client["last_active_session_id"]
44
72
  client["sessions"].find do |sess|
45
- sess["id"] == sess_id
73
+ sess["id"] == @session_id
46
74
  end
47
75
  end
48
76
  end
49
77
  end
50
78
 
51
79
  def fetch_user(user_id)
52
- sdk = clerk_sdk
53
80
  cached_fetch("clerk_user:#{user_id}") do
54
81
  sdk.users.find(user_id)
55
82
  end
@@ -0,0 +1,168 @@
1
+ require "clerk"
2
+
3
+ module Clerk
4
+ class RackMiddlewareV2
5
+ class ProxyV2
6
+ CACHE_TTL = 60 # seconds
7
+
8
+ attr_reader :session_claims, :session_token
9
+
10
+ def initialize(session_claims: nil, session_token: nil)
11
+ @session_claims = session_claims
12
+ @session_token = session_token
13
+ @session = nil
14
+ end
15
+
16
+ def session
17
+ return nil if @session_claims.nil?
18
+
19
+ @session ||= verify_session
20
+ end
21
+
22
+ def verify_session
23
+ return nil if @session_claims.nil?
24
+
25
+ sdk.sessions.verify_token(@session_claims["sid"], @session_token)
26
+ end
27
+
28
+ def user
29
+ return nil if user_id.nil?
30
+
31
+ @user ||= fetch_user(user_id)
32
+ end
33
+
34
+ def user_id
35
+ return nil if @session_claims.nil?
36
+
37
+ @session_claims["sub"]
38
+ end
39
+
40
+ private
41
+
42
+ def fetch_user(user_id)
43
+ cached_fetch("clerk_user:#{user_id}") do
44
+ sdk.users.find(user_id)
45
+ end
46
+ end
47
+
48
+ def cached_fetch(key, &block)
49
+ if store = Clerk.configuration.middleware_cache_store
50
+ store.fetch(key, expires_in: CACHE_TTL, &block)
51
+ else
52
+ yield
53
+ end
54
+ end
55
+
56
+ def sdk
57
+ @sdk ||= Clerk::SDK.new
58
+ end
59
+ end
60
+
61
+ def initialize(app)
62
+ @app = app
63
+ end
64
+
65
+ def call(env)
66
+ @env = env
67
+ @req = Rack::Request.new(env)
68
+ @env["clerk"] = ProxyV2.new
69
+ @header_token = @req.env["HTTP_AUTHORIZATION"]&.strip
70
+ @cookie_token = @req.cookies["__session"]
71
+ @client_uat = @req.cookies["__client_uat"]
72
+
73
+ ##########################################################################
74
+ # #
75
+ # HEADER AUTHENTICATION #
76
+ # #
77
+ ##########################################################################
78
+ if @header_token
79
+ return signed_out if !sdk.decode_token(@header_token) # malformed JWT
80
+
81
+ token = verify_token(@header_token)
82
+ return signed_in(token, @header_token) if token
83
+
84
+ # Clerk.js should refresh the token and retry
85
+ return unknown(interstitial: false)
86
+ end
87
+
88
+ # in cross-origin XHRs the use of Authorization header is mandatory.
89
+ if cross_origin_request?(@req) && @header_token.nil?
90
+ return signed_out
91
+ end
92
+
93
+ ##########################################################################
94
+ # #
95
+ # COOKIE AUTHENTICATION #
96
+ # #
97
+ ##########################################################################
98
+ if development_or_staging? && (@req.referrer.nil? || cross_origin_request?(@req))
99
+ return unknown(interstitial: true)
100
+ end
101
+
102
+ if production? && @client_uat.nil?
103
+ return signed_out
104
+ end
105
+
106
+ if @client_uat == "0"
107
+ return signed_out
108
+ end
109
+
110
+ token = verify_token(@cookie_token)
111
+
112
+ if token && token["iat"] && @client_uat && Integer(@client_uat) <= token["iat"]
113
+ return signed_in(token, @cookie_token)
114
+ end
115
+
116
+ unknown(interstitial: true)
117
+ end
118
+
119
+ private
120
+
121
+ # Outcome A
122
+ def signed_in(claims, token)
123
+ @env["clerk"] = ProxyV2.new(session_claims: claims, session_token: token)
124
+
125
+ @app.call(@env)
126
+ end
127
+
128
+ # Outcome B
129
+ def signed_out
130
+ @app.call(@env)
131
+ end
132
+
133
+ # Outcome C
134
+ def unknown(interstitial: false)
135
+ return [401, {}, []] if !interstitial
136
+
137
+ # Load Clerk.js to update the __session and __client_uat cookies.
138
+ [401, {"Content-Type" => "text/html"}, [sdk.interstitial]]
139
+ end
140
+
141
+ def development_or_staging?
142
+ Clerk.configuration.api_key.start_with?("test_")
143
+ end
144
+
145
+ def production?
146
+ !development_or_staging?
147
+ end
148
+
149
+ def cross_origin_request?(req)
150
+ origin = req.env["HTTP_ORIGIN"]
151
+ origin && origin != req.host
152
+ end
153
+
154
+ def verify_token(token)
155
+ return false if token.nil? || token.strip.empty?
156
+
157
+ begin
158
+ @session = sdk.verify_token(token)
159
+ rescue JWT::DecodeError, JWT::RequiredDependencyError => e
160
+ false
161
+ end
162
+ end
163
+
164
+ def sdk
165
+ @sdk ||= Clerk::SDK.new
166
+ end
167
+ end
168
+ end
data/lib/clerk/railtie.rb CHANGED
@@ -1,17 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  #
3
3
  require_relative "rack_middleware"
4
+ require_relative "rack_middleware_v2"
4
5
 
5
6
  module Clerk
6
7
  class Railtie < ::Rails::Railtie
7
8
  initializer "clerk_railtie.configure_rails_initialization" do |app|
8
- app.middleware.use Clerk::RackMiddleware
9
- end
10
-
11
- config.to_prepare do
12
- Clerk.configure do |c|
13
- c.middleware_cache_store ||= Rails.cache
14
- end
9
+ app.middleware.use Clerk::RackMiddlewareV2
15
10
  end
16
11
  end
17
12
  end
@@ -0,0 +1,18 @@
1
+ require "forwardable"
2
+ require_relative "plural_resource"
3
+
4
+ module Clerk
5
+ module Resources
6
+ class JWKS
7
+ extend Forwardable
8
+
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def all(timeout: 5)
14
+ @client.request(:get, "jwks", timeout: timeout)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -7,10 +7,15 @@ module Clerk
7
7
  extend Forwardable
8
8
 
9
9
  def initialize(client)
10
+ @client = client
10
11
  @resource = PluralResource.new(client, "users")
11
12
  end
12
13
 
13
14
  def_delegators :@resource, :all, :find, :update, :delete
15
+
16
+ def oauth_access_token(user_id, provider)
17
+ @client.request(:get, "#{@resource.resource_path(user_id)}/oauth_access_tokens/#{provider}")
18
+ end
14
19
  end
15
20
  end
16
21
  end
@@ -5,3 +5,4 @@ require_relative "resources/emails"
5
5
  require_relative "resources/sessions"
6
6
  require_relative "resources/sms_messages"
7
7
  require_relative "resources/users"
8
+ require_relative "resources/jwks"
data/lib/clerk/sdk.rb CHANGED
@@ -4,6 +4,7 @@ require "faraday"
4
4
  require "logger"
5
5
  require "net/http"
6
6
  require "json"
7
+ require "jwt"
7
8
 
8
9
  require_relative "resources/allowlist_identifiers"
9
10
  require_relative "resources/allowlist"
@@ -12,6 +13,8 @@ require_relative "resources/emails"
12
13
  require_relative "resources/sessions"
13
14
  require_relative "resources/sms_messages"
14
15
  require_relative "resources/users"
16
+ require_relative "resources/users"
17
+ require_relative "resources/jwks"
15
18
  require_relative "errors"
16
19
 
17
20
  module Clerk
@@ -20,8 +23,13 @@ module Clerk
20
23
  "User-Agent" => "Clerk/#{Clerk::VERSION}; Faraday/#{Faraday::VERSION}; Ruby/#{RUBY_VERSION}"
21
24
  }
22
25
 
26
+ # How often (in seconds) should JWKs be refreshed
27
+ JWKS_CACHE_LIFETIME = 3600 # 1 hour
28
+
23
29
  def initialize(api_key: nil, base_url: nil, logger: nil, ssl_verify: true,
24
30
  connection: nil)
31
+ @jwks_fetched_at = nil
32
+
25
33
  if connection # Inject a Faraday::Connection for testing or full control over Faraday
26
34
  @conn = connection
27
35
  return
@@ -48,16 +56,26 @@ module Clerk
48
56
  end
49
57
  end
50
58
 
51
- def request(method, path, query: [], body: nil)
59
+ def request(method, path, query: [], body: nil, timeout: nil)
52
60
  response = case method
53
61
  when :get
54
- @conn.get(path, query)
62
+ @conn.get(path, query) do |req|
63
+ req.options.timeout = timeout if timeout
64
+ end
55
65
  when :post
56
- @conn.post(path, body)
66
+ @conn.post(path, body) do |req|
67
+ req.body = body
68
+ req.options.timeout = timeout if timeout
69
+ end
57
70
  when :patch
58
- @conn.patch(path, body)
71
+ @conn.patch(path, body) do |req|
72
+ req.body = body
73
+ req.options.timeout = timeout if timeout
74
+ end
59
75
  when :delete
60
- @conn.delete(path)
76
+ @conn.delete(path) do |req|
77
+ req.options.timeout = timeout if timeout
78
+ end
61
79
  end
62
80
 
63
81
  body = if response["Content-Type"] == "application/json"
@@ -106,5 +124,50 @@ module Clerk
106
124
  def users
107
125
  Resources::Users.new(self)
108
126
  end
127
+
128
+ def jwks
129
+ Resources::JWKS.new(self)
130
+ end
131
+
132
+ def interstitial(refresh=false)
133
+ request(:get, "internal/interstitial")
134
+ end
135
+
136
+ # Returns the decoded JWT payload without verifying if the signature is
137
+ # valid.
138
+ #
139
+ # WARNING: This will not verify whether the signature is valid. You
140
+ # should not use this for untrusted messages! You most likely want to use
141
+ # verify_token.
142
+ def decode_token(token)
143
+ JWT.decode(token, nil, false).first
144
+ end
145
+
146
+ # Decode the JWT and verify it's valid (verify claims, signature etc.) using
147
+ # the provided algorithms.
148
+ #
149
+ # JWKS are cached for JWKS_CACHE_LIFETIME seconds, in order to avoid
150
+ # unecessary roundtrips. In order to invalidate the cache, pass
151
+ # `force_refresh_jwks: true`.
152
+ #
153
+ # A timeout for the request to the JWKs endpoint can be set with the
154
+ # `timeout` argument.
155
+ def verify_token(token, force_refresh_jwks: false, algorithms: ['RS256'], timeout: 5)
156
+ jwk_loader = ->(options) do
157
+ @cached_jwks = nil if options[:invalidate] || force_refresh_jwks
158
+ @cached_jwks = nil if @jwks_fetched_at && Time.now.to_i - @jwks_fetched_at > JWKS_CACHE_LIFETIME
159
+
160
+ @cached_jwks ||= begin
161
+ keys = jwks.all["keys"]
162
+ @jwks_fetched_at = Time.now.to_i
163
+
164
+ # JWT.decode requires that the 'keys' key in the Hash is a symbol (as
165
+ # opposed to a string which our SDK returns by default)
166
+ { keys: keys }
167
+ end
168
+ end
169
+
170
+ JWT.decode(token, nil, true, algorithms: algorithms, jwks: jwk_loader).first
171
+ end
109
172
  end
110
173
  end
data/lib/clerk/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clerk
4
- VERSION = "1.0.0"
4
+ VERSION = "2.0.0.alpha.1"
5
5
  end
data/lib/clerk.rb CHANGED
@@ -5,12 +5,13 @@ require_relative "clerk/sdk"
5
5
 
6
6
  module Clerk
7
7
  class << self
8
- attr_accessor :configuration
9
-
10
8
  def configure
11
- self.configuration ||= Config.new
12
9
  yield(configuration)
13
10
  end
11
+
12
+ def configuration
13
+ @configuration ||= Config.new
14
+ end
14
15
  end
15
16
 
16
17
  class Config
@@ -19,7 +20,7 @@ module Clerk
19
20
 
20
21
  def initialize
21
22
  @base_url = ENV.fetch("CLERK_API_BASE", PRODUCTION_BASE_URL)
22
- @api_key = ENV.fetch("CLERK_API_KEY")
23
+ @api_key = ENV["CLERK_API_KEY"]
23
24
  end
24
25
  end
25
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clerk-sdk-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0.alpha.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clerk
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-27 00:00:00.000000000 Z
11
+ date: 2021-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -24,6 +24,48 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: jwt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '11.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '11.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: timecop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.4
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.9.4
27
69
  description: Client SDK for the Clerk backend API.
28
70
  email:
29
71
  - ruby-sdk@clerk.dev
@@ -33,6 +75,7 @@ extra_rdoc_files: []
33
75
  files:
34
76
  - ".github/workflows/main.yml"
35
77
  - ".gitignore"
78
+ - CHANGELOG.md
36
79
  - Gemfile
37
80
  - Gemfile.lock
38
81
  - LICENSE.txt
@@ -44,13 +87,16 @@ files:
44
87
  - lib/clerk.rb
45
88
  - lib/clerk/authenticatable.rb
46
89
  - lib/clerk/errors.rb
90
+ - lib/clerk/proxy.rb
47
91
  - lib/clerk/rack_middleware.rb
92
+ - lib/clerk/rack_middleware_v2.rb
48
93
  - lib/clerk/railtie.rb
49
94
  - lib/clerk/resources.rb
50
95
  - lib/clerk/resources/allowlist.rb
51
96
  - lib/clerk/resources/allowlist_identifiers.rb
52
97
  - lib/clerk/resources/clients.rb
53
98
  - lib/clerk/resources/emails.rb
99
+ - lib/clerk/resources/jwks.rb
54
100
  - lib/clerk/resources/plural_resource.rb
55
101
  - lib/clerk/resources/sessions.rb
56
102
  - lib/clerk/resources/singular_resource.rb
@@ -66,7 +112,7 @@ metadata:
66
112
  homepage_uri: https://github.com/clerkinc/clerk-sdk-ruby
67
113
  source_code_uri: https://github.com/clerkinc/clerk-sdk-ruby
68
114
  changelog_uri: https://github.com/clerkinc/clerk-sdk-ruby/blob/main/CHANGELOG.md
69
- post_install_message:
115
+ post_install_message:
70
116
  rdoc_options: []
71
117
  require_paths:
72
118
  - lib
@@ -77,12 +123,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
77
123
  version: 2.4.0
78
124
  required_rubygems_version: !ruby/object:Gem::Requirement
79
125
  requirements:
80
- - - ">="
126
+ - - ">"
81
127
  - !ruby/object:Gem::Version
82
- version: '0'
128
+ version: 1.3.1
83
129
  requirements: []
84
- rubygems_version: 3.2.15
85
- signing_key:
130
+ rubygems_version: 3.2.5
131
+ signing_key:
86
132
  specification_version: 4
87
133
  summary: Clerk SDK for Ruby.
88
134
  test_files: []