clerk-sdk-ruby 2.0.3 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 692cc6e564176d884eb9697a0bfe4a02affda01032c73a9bf704700e45265e4f
4
- data.tar.gz: 1f425dd5b92b2bb51e20661d2415c4c1d094c781c2b4a7c0b0199dce29897c74
3
+ metadata.gz: dd893298c9206f7cacd07fd7c8db9278c2f1c8353d43582a3275ac2a98558bfb
4
+ data.tar.gz: 7dc3976d5c922f648df6fbf77afd43ea1d2b185d828d23617dad0ac960ea9503
5
5
  SHA512:
6
- metadata.gz: f6497dff3fb8bc8f9a32747dd790a8481571d5b460ee83737c9ca6e43ef98db1dfa5fb8277d10f79b516c62fc58233088dcebd3aa3fd7770ba1f6311d7881b57
7
- data.tar.gz: 8ed32ac76cdd9d9c3615375310808919b139bfc22480a2cdcd05cd8ec1a2b3ce68c62864576c91694888e2164856c341577dc89a2adede157996e68421b3fa1f
6
+ metadata.gz: 17db456db28fc892f2df82e7ee84d2f3799a804c223e7b1e815fc7f6b0ec5a439ac23c7a781495fa8fc5ff0d3b6d2b52171081349f7ce9f27f53bcb1251d91e1
7
+ data.tar.gz: 02fb997d526e9d4116558c88201f2da5db5c8cbeef947dd6aac73373b8d8ed235225f661f9f8d11a538c346140edd66bb8a9b3d503949b226195f374fc86e51e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## unreleased
2
2
 
3
+ ## 2.1.2 - 2022-08-26
4
+
5
+ - fix: Gracefully handle invalid JSON in Authorization header [https://github.com/clerkinc/clerk-sdk-ruby/pull/16]
6
+
7
+ ## 2.1.1 - 2022-02-24
8
+
9
+ - fix: Make Authv2 middleware thread-safe
10
+
3
11
  ## 2.0.0 - 2021-10-21
4
12
 
5
13
  This release introduces the new networkless middleware which works with the new
data/README.md CHANGED
@@ -1,20 +1,25 @@
1
1
  # Clerk Ruby SDK
2
2
 
3
+
3
4
  Thank you for choosing [Clerk](https://clerk.dev/) for your authentication,
4
5
  session & user management needs!
5
6
 
6
7
  This SDK allows you to call the Clerk Backend API from Ruby code without having
7
8
  to implement the calls yourself.
8
9
 
9
- ---------
10
-
11
- **Note**: This is the v2 branch, which requires that you use [Auth
10
+ **Note**: You're looking at the main branch, which requires that you use [Auth
12
11
  v2](https://docs.clerk.dev/main-concepts/auth-v2).
13
12
 
14
- If you're looking for the legacy authentication scheme (Auth v1), refer to the
15
- [`main`](https://github.com/clerkinc/clerk-sdk-ruby/tree/main) branch.
13
+ If you're looking for the legacy authentication scheme, refer to the
14
+ [`v1`](https://github.com/clerkinc/clerk-sdk-ruby/tree/v1) branch.
15
+
16
+ ---
17
+
18
+ **Clerk is Hiring!**
19
+
20
+ Would you like to work on Open Source software and help maintain this repository? Apply today https://apply.workable.com/clerk-dev/.
16
21
 
17
- ----------
22
+ ---
18
23
 
19
24
  ## Installation
20
25
 
@@ -10,7 +10,7 @@ module Clerk
10
10
  # the Session object. Subsequent calls to this method will return the cached
11
11
  # Session object.
12
12
  #
13
- # NOTE: For better performance, you can instead use `#clerk_session_claims`
13
+ # NOTE: For better performance, you can instead use `#clerk_verified_session_claims`
14
14
  # which already contains the verified claims as retrieved from the session
15
15
  # token.
16
16
  def clerk_session
@@ -20,7 +20,7 @@ module Clerk
20
20
  # Makes a request to the Clerk API to verify the session again. Returns the
21
21
  # session object as fetched from the API.
22
22
  #
23
- # NOTE: For better performance, you can instead use `#clerk_session_claims`
23
+ # NOTE: For better performance, you can instead use `#clerk_verified_session_claims`
24
24
  # which already contains the verified claims as retrieved from the session
25
25
  # token.
26
26
  #
@@ -1,93 +1,107 @@
1
1
  require "clerk"
2
2
 
3
3
  module Clerk
4
- class RackMiddlewareV2
5
- class ProxyV2
6
- CACHE_TTL = 60 # seconds
4
+ class ProxyV2
5
+ CACHE_TTL = 60 # seconds
7
6
 
8
- attr_reader :session_claims, :session_token
7
+ attr_reader :session_claims, :session_token
9
8
 
10
- def initialize(session_claims: nil, session_token: nil)
11
- @session_claims = session_claims
12
- @session_token = session_token
13
- @session = nil
14
- end
9
+ def initialize(session_claims: nil, session_token: nil)
10
+ @session_claims = session_claims
11
+ @session_token = session_token
12
+ @session = nil
13
+ end
15
14
 
16
- def session
17
- return nil if @session_claims.nil?
15
+ def session
16
+ return nil if @session_claims.nil?
18
17
 
19
- @session ||= verify_session
20
- end
18
+ @session ||= verify_session
19
+ end
21
20
 
22
- def verify_session
23
- return nil if @session_claims.nil?
21
+ def verify_session
22
+ return nil if @session_claims.nil?
24
23
 
25
- sdk.sessions.verify_token(@session_claims["sid"], @session_token)
26
- end
24
+ sdk.sessions.verify_token(@session_claims["sid"], @session_token)
25
+ end
27
26
 
28
- def user
29
- return nil if user_id.nil?
27
+ def user
28
+ return nil if user_id.nil?
30
29
 
31
- @user ||= fetch_user(user_id)
32
- end
30
+ @user ||= fetch_user(user_id)
31
+ end
33
32
 
34
- def user_id
35
- return nil if @session_claims.nil?
33
+ def user_id
34
+ return nil if @session_claims.nil?
36
35
 
37
- @session_claims["sub"]
38
- end
36
+ @session_claims["sub"]
37
+ end
39
38
 
40
- private
39
+ private
41
40
 
42
- def fetch_user(user_id)
43
- cached_fetch("clerk_user:#{user_id}") do
44
- sdk.users.find(user_id)
45
- end
41
+ def fetch_user(user_id)
42
+ cached_fetch("clerk_user:#{user_id}") do
43
+ sdk.users.find(user_id)
46
44
  end
45
+ end
47
46
 
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
47
+ def cached_fetch(key, &block)
48
+ if store = Clerk.configuration.middleware_cache_store
49
+ store.fetch(key, expires_in: CACHE_TTL, &block)
50
+ else
51
+ yield
54
52
  end
53
+ end
55
54
 
56
- def sdk
57
- @sdk ||= Clerk::SDK.new
58
- end
55
+ def sdk
56
+ @sdk ||= Clerk::SDK.new
59
57
  end
58
+ end
60
59
 
60
+ class RackMiddlewareV2
61
61
  def initialize(app)
62
62
  @app = app
63
63
  end
64
64
 
65
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"]
66
+ env = env
67
+ req = Rack::Request.new(env)
68
+ env["clerk"] = Clerk::ProxyV2.new
69
+ header_token = req.env["HTTP_AUTHORIZATION"]
70
+ header_token = header_token.strip.sub(/\ABearer /, '') if header_token
71
+ cookie_token = req.cookies["__session"]
72
+ client_uat = req.cookies["__client_uat"]
72
73
 
73
74
  ##########################################################################
74
75
  # #
75
76
  # HEADER AUTHENTICATION #
76
77
  # #
77
78
  ##########################################################################
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
79
+ if header_token
80
+ begin
81
+ return signed_out(env) if !sdk.decode_token(header_token) # malformed JWT
82
+ rescue JWT::DecodeError
83
+ return signed_out(env) # malformed JSON authorization header
84
+ end
85
+
86
+ token = verify_token(header_token)
87
+ return signed_in(env, token, header_token) if token
83
88
 
84
89
  # Clerk.js should refresh the token and retry
85
90
  return unknown(interstitial: false)
86
91
  end
87
92
 
88
93
  # in cross-origin XHRs the use of Authorization header is mandatory.
89
- if cross_origin_request?(@req)
90
- return signed_out
94
+ if cross_origin_request?(req)
95
+ return signed_out(env)
96
+ end
97
+
98
+ if development_or_staging? && !browser_request?(req)
99
+ # the interstitial won't work if the user agent is not a browser, so
100
+ # short-circuit and avoid rendering it
101
+ #
102
+ # We only limit this to dev/stg because we're not yet sure how robust
103
+ # this strategy is, yet. In the future, we might enable it for prod too.
104
+ return signed_out(env)
91
105
  end
92
106
 
93
107
  ##########################################################################
@@ -95,22 +109,22 @@ module Clerk
95
109
  # COOKIE AUTHENTICATION #
96
110
  # #
97
111
  ##########################################################################
98
- if development_or_staging? && (@req.referrer.nil? || cross_origin_request?(@req))
112
+ if development_or_staging? && (req.referrer.nil? || cross_origin_request?(req))
99
113
  return unknown(interstitial: true)
100
114
  end
101
115
 
102
- if production? && @client_uat.nil?
103
- return signed_out
116
+ if production? && client_uat.nil?
117
+ return signed_out(env)
104
118
  end
105
119
 
106
- if @client_uat == "0"
107
- return signed_out
120
+ if client_uat == "0"
121
+ return signed_out(env)
108
122
  end
109
123
 
110
- token = verify_token(@cookie_token)
124
+ token = verify_token(cookie_token)
111
125
 
112
- if token && token["iat"] && @client_uat && Integer(@client_uat) <= token["iat"]
113
- return signed_in(token, @cookie_token)
126
+ if token && token["iat"] && client_uat && Integer(client_uat) <= token["iat"]
127
+ return signed_in(env, token, cookie_token)
114
128
  end
115
129
 
116
130
  unknown(interstitial: true)
@@ -119,15 +133,15 @@ module Clerk
119
133
  private
120
134
 
121
135
  # Outcome A
122
- def signed_in(claims, token)
123
- @env["clerk"] = ProxyV2.new(session_claims: claims, session_token: token)
136
+ def signed_in(env, claims, token)
137
+ env["clerk"] = ProxyV2.new(session_claims: claims, session_token: token)
124
138
 
125
- @app.call(@env)
139
+ @app.call(env)
126
140
  end
127
141
 
128
142
  # Outcome B
129
- def signed_out
130
- @app.call(@env)
143
+ def signed_out(env)
144
+ @app.call(env)
131
145
  end
132
146
 
133
147
  # Outcome C
@@ -153,7 +167,7 @@ module Clerk
153
167
  return false if origin.nil?
154
168
 
155
169
  # strip scheme
156
- origin = origin.strip.sub(/(^\w+:|^)\/\//, '')
170
+ origin = origin.strip.sub(/\A(\w+:)?\/\//, '')
157
171
  return false if origin.empty?
158
172
 
159
173
  # Rack's host and port helpers are reverse-proxy-aware; that
@@ -164,18 +178,24 @@ module Clerk
164
178
  origin != request_host
165
179
  end
166
180
 
181
+ def browser_request?(req)
182
+ user_agent = req.env["HTTP_USER_AGENT"]
183
+
184
+ !user_agent.nil? && user_agent.starts_with?("Mozilla/")
185
+ end
186
+
167
187
  def verify_token(token)
168
188
  return false if token.nil? || token.strip.empty?
169
189
 
170
190
  begin
171
- @session = sdk.verify_token(token)
191
+ sdk.verify_token(token)
172
192
  rescue JWT::DecodeError, JWT::RequiredDependencyError => e
173
193
  false
174
194
  end
175
195
  end
176
196
 
177
197
  def sdk
178
- @sdk ||= Clerk::SDK.new
198
+ Clerk::SDK.new
179
199
  end
180
200
  end
181
201
  end
data/lib/clerk/sdk.rb CHANGED
@@ -20,7 +20,8 @@ require_relative "errors"
20
20
  module Clerk
21
21
  class SDK
22
22
  DEFAULT_HEADERS = {
23
- "User-Agent" => "Clerk/#{Clerk::VERSION}; Faraday/#{Faraday::VERSION}; Ruby/#{RUBY_VERSION}"
23
+ "User-Agent" => "Clerk/#{Clerk::VERSION}; Faraday/#{Faraday::VERSION}; Ruby/#{RUBY_VERSION}",
24
+ "X-Clerk-SDK" => "ruby/#{Clerk::VERSION}"
24
25
  }
25
26
 
26
27
  # How often (in seconds) should JWKs be refreshed
data/lib/clerk/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clerk
4
- VERSION = "2.0.3"
4
+ VERSION = "2.1.2"
5
5
  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: 2.0.3
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clerk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-22 00:00:00.000000000 Z
11
+ date: 2022-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday