clerk-sdk-ruby 4.0.0.beta2 → 4.0.0.beta4

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.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +3 -0
  3. data/.github/workflows/main.yml +22 -14
  4. data/.gitignore +7 -1
  5. data/.rspec +3 -0
  6. data/.ruby-version +1 -0
  7. data/CHANGELOG.md +25 -0
  8. data/Gemfile +26 -3
  9. data/Gemfile.lock +269 -13
  10. data/Guardfile +14 -0
  11. data/README.md +71 -11
  12. data/Rakefile +50 -6
  13. data/apps/rack/app.rb +67 -0
  14. data/apps/rack/config.ru +17 -0
  15. data/apps/rack/middleware/disable_paths.rb +13 -0
  16. data/apps/rails-api/.dockerignore +41 -0
  17. data/apps/rails-api/.gitattributes +9 -0
  18. data/apps/rails-api/.gitignore +32 -0
  19. data/apps/rails-api/.kamal/hooks/docker-setup.sample +3 -0
  20. data/apps/rails-api/.kamal/hooks/post-deploy.sample +14 -0
  21. data/apps/rails-api/.kamal/hooks/post-proxy-reboot.sample +3 -0
  22. data/apps/rails-api/.kamal/hooks/pre-build.sample +51 -0
  23. data/apps/rails-api/.kamal/hooks/pre-connect.sample +47 -0
  24. data/apps/rails-api/.kamal/hooks/pre-deploy.sample +109 -0
  25. data/apps/rails-api/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  26. data/apps/rails-api/.kamal/secrets +17 -0
  27. data/apps/rails-api/.rubocop.yml +8 -0
  28. data/apps/rails-api/.ruby-version +1 -0
  29. data/apps/rails-api/Dockerfile +69 -0
  30. data/apps/rails-api/Gemfile +54 -0
  31. data/apps/rails-api/Gemfile.lock +374 -0
  32. data/apps/rails-api/README.md +24 -0
  33. data/apps/rails-api/Rakefile +6 -0
  34. data/apps/rails-api/app/controllers/application_controller.rb +3 -0
  35. data/apps/rails-api/app/controllers/home_controller.rb +5 -0
  36. data/apps/rails-api/app/jobs/application_job.rb +7 -0
  37. data/apps/rails-api/app/mailers/application_mailer.rb +4 -0
  38. data/apps/rails-api/app/models/application_record.rb +3 -0
  39. data/apps/rails-api/app/views/layouts/mailer.html.erb +13 -0
  40. data/apps/rails-api/app/views/layouts/mailer.text.erb +1 -0
  41. data/apps/rails-api/bin/brakeman +7 -0
  42. data/apps/rails-api/bin/bundle +109 -0
  43. data/apps/rails-api/bin/dev +2 -0
  44. data/apps/rails-api/bin/docker-entrypoint +14 -0
  45. data/apps/rails-api/bin/jobs +6 -0
  46. data/apps/rails-api/bin/kamal +27 -0
  47. data/apps/rails-api/bin/rails +4 -0
  48. data/apps/rails-api/bin/rake +4 -0
  49. data/apps/rails-api/bin/rubocop +8 -0
  50. data/apps/rails-api/bin/setup +34 -0
  51. data/apps/rails-api/bin/thrust +5 -0
  52. data/apps/rails-api/config/application.rb +36 -0
  53. data/apps/rails-api/config/boot.rb +4 -0
  54. data/apps/rails-api/config/cable.yml +17 -0
  55. data/apps/rails-api/config/cache.yml +16 -0
  56. data/apps/rails-api/config/credentials.yml.enc +1 -0
  57. data/apps/rails-api/config/database.yml +41 -0
  58. data/apps/rails-api/config/deploy.yml +116 -0
  59. data/apps/rails-api/config/environment.rb +5 -0
  60. data/apps/rails-api/config/environments/development.rb +70 -0
  61. data/apps/rails-api/config/environments/production.rb +88 -0
  62. data/apps/rails-api/config/environments/test.rb +53 -0
  63. data/apps/rails-api/config/initializers/cors.rb +16 -0
  64. data/apps/rails-api/config/initializers/filter_parameter_logging.rb +8 -0
  65. data/apps/rails-api/config/initializers/inflections.rb +16 -0
  66. data/apps/rails-api/config/locales/en.yml +31 -0
  67. data/apps/rails-api/config/puma.rb +41 -0
  68. data/apps/rails-api/config/queue.yml +18 -0
  69. data/apps/rails-api/config/recurring.yml +10 -0
  70. data/apps/rails-api/config/routes.rb +10 -0
  71. data/apps/rails-api/config/storage.yml +34 -0
  72. data/apps/rails-api/config.ru +6 -0
  73. data/apps/rails-api/db/cable_schema.rb +11 -0
  74. data/apps/rails-api/db/cache_schema.rb +14 -0
  75. data/apps/rails-api/db/queue_schema.rb +129 -0
  76. data/apps/rails-api/db/seeds.rb +9 -0
  77. data/apps/rails-api/public/robots.txt +1 -0
  78. data/apps/rails-api/test/controllers/home_controller_test.rb +7 -0
  79. data/apps/rails-api/test/test_helper.rb +15 -0
  80. data/apps/rails-full/.dockerignore +47 -0
  81. data/apps/rails-full/.gitattributes +9 -0
  82. data/apps/rails-full/.gitignore +34 -0
  83. data/apps/rails-full/.kamal/hooks/docker-setup.sample +3 -0
  84. data/apps/rails-full/.kamal/hooks/post-deploy.sample +14 -0
  85. data/apps/rails-full/.kamal/hooks/post-proxy-reboot.sample +3 -0
  86. data/apps/rails-full/.kamal/hooks/pre-build.sample +51 -0
  87. data/apps/rails-full/.kamal/hooks/pre-connect.sample +47 -0
  88. data/apps/rails-full/.kamal/hooks/pre-deploy.sample +109 -0
  89. data/apps/rails-full/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  90. data/apps/rails-full/.kamal/secrets +17 -0
  91. data/apps/rails-full/.rubocop.yml +8 -0
  92. data/apps/rails-full/.ruby-version +1 -0
  93. data/apps/rails-full/Dockerfile +72 -0
  94. data/apps/rails-full/Gemfile +70 -0
  95. data/apps/rails-full/Gemfile.lock +429 -0
  96. data/apps/rails-full/README.md +24 -0
  97. data/apps/rails-full/Rakefile +6 -0
  98. data/apps/rails-full/app/assets/stylesheets/application.css +10 -0
  99. data/apps/rails-full/app/controllers/application_controller.rb +6 -0
  100. data/apps/rails-full/app/controllers/home_controller.rb +11 -0
  101. data/apps/rails-full/app/helpers/application_helper.rb +2 -0
  102. data/apps/rails-full/app/helpers/home_helper.rb +2 -0
  103. data/apps/rails-full/app/javascript/application.js +3 -0
  104. data/apps/rails-full/app/javascript/controllers/application.js +9 -0
  105. data/apps/rails-full/app/javascript/controllers/hello_controller.js +7 -0
  106. data/apps/rails-full/app/javascript/controllers/index.js +4 -0
  107. data/apps/rails-full/app/jobs/application_job.rb +7 -0
  108. data/apps/rails-full/app/mailers/application_mailer.rb +4 -0
  109. data/apps/rails-full/app/models/application_record.rb +3 -0
  110. data/apps/rails-full/app/views/home/index.html.erb +7 -0
  111. data/apps/rails-full/app/views/layouts/application.html.erb +60 -0
  112. data/apps/rails-full/app/views/layouts/mailer.html.erb +13 -0
  113. data/apps/rails-full/app/views/layouts/mailer.text.erb +1 -0
  114. data/apps/rails-full/app/views/pwa/manifest.json.erb +22 -0
  115. data/apps/rails-full/app/views/pwa/service-worker.js +26 -0
  116. data/apps/rails-full/bin/brakeman +7 -0
  117. data/apps/rails-full/bin/bundle +109 -0
  118. data/apps/rails-full/bin/dev +2 -0
  119. data/apps/rails-full/bin/docker-entrypoint +14 -0
  120. data/apps/rails-full/bin/importmap +4 -0
  121. data/apps/rails-full/bin/jobs +6 -0
  122. data/apps/rails-full/bin/kamal +27 -0
  123. data/apps/rails-full/bin/rails +4 -0
  124. data/apps/rails-full/bin/rake +4 -0
  125. data/apps/rails-full/bin/rubocop +8 -0
  126. data/apps/rails-full/bin/setup +34 -0
  127. data/apps/rails-full/bin/thrust +5 -0
  128. data/apps/rails-full/config/application.rb +31 -0
  129. data/apps/rails-full/config/boot.rb +4 -0
  130. data/apps/rails-full/config/cable.yml +17 -0
  131. data/apps/rails-full/config/cache.yml +16 -0
  132. data/apps/rails-full/config/credentials.yml.enc +1 -0
  133. data/apps/rails-full/config/database.yml +41 -0
  134. data/apps/rails-full/config/deploy.yml +116 -0
  135. data/apps/rails-full/config/environment.rb +5 -0
  136. data/apps/rails-full/config/environments/development.rb +72 -0
  137. data/apps/rails-full/config/environments/production.rb +91 -0
  138. data/apps/rails-full/config/environments/test.rb +53 -0
  139. data/apps/rails-full/config/importmap.rb +7 -0
  140. data/apps/rails-full/config/initializers/assets.rb +7 -0
  141. data/apps/rails-full/config/initializers/clerk.rb +4 -0
  142. data/apps/rails-full/config/initializers/content_security_policy.rb +25 -0
  143. data/apps/rails-full/config/initializers/filter_parameter_logging.rb +8 -0
  144. data/apps/rails-full/config/initializers/inflections.rb +16 -0
  145. data/apps/rails-full/config/locales/en.yml +31 -0
  146. data/apps/rails-full/config/puma.rb +41 -0
  147. data/apps/rails-full/config/queue.yml +18 -0
  148. data/apps/rails-full/config/recurring.yml +10 -0
  149. data/apps/rails-full/config/routes.rb +15 -0
  150. data/apps/rails-full/config/storage.yml +34 -0
  151. data/apps/rails-full/config.ru +6 -0
  152. data/apps/rails-full/db/cable_schema.rb +11 -0
  153. data/apps/rails-full/db/cache_schema.rb +14 -0
  154. data/apps/rails-full/db/queue_schema.rb +129 -0
  155. data/apps/rails-full/db/seeds.rb +9 -0
  156. data/apps/rails-full/public/400.html +114 -0
  157. data/apps/rails-full/public/404.html +114 -0
  158. data/apps/rails-full/public/406-unsupported-browser.html +114 -0
  159. data/apps/rails-full/public/422.html +114 -0
  160. data/apps/rails-full/public/500.html +114 -0
  161. data/apps/rails-full/public/icon.png +0 -0
  162. data/apps/rails-full/public/icon.svg +3 -0
  163. data/apps/rails-full/public/robots.txt +1 -0
  164. data/apps/rails-full/test/application_system_test_case.rb +5 -0
  165. data/apps/rails-full/test/controllers/home_controller_test.rb +7 -0
  166. data/apps/rails-full/test/test_helper.rb +15 -0
  167. data/apps/sinatra/app.rb +29 -0
  168. data/apps/sinatra/config.ru +2 -0
  169. data/apps/sinatra/views/index.erb +44 -0
  170. data/clerk-sdk-ruby.gemspec +2 -1
  171. data/lib/clerk/authenticatable.rb +14 -79
  172. data/lib/clerk/authenticate_context.rb +164 -179
  173. data/lib/clerk/authenticate_request.rb +238 -230
  174. data/lib/clerk/configuration.rb +78 -0
  175. data/lib/clerk/constants.rb +68 -46
  176. data/lib/clerk/error.rb +17 -0
  177. data/lib/clerk/jwks_cache.rb +27 -22
  178. data/lib/clerk/proxy.rb +135 -0
  179. data/lib/clerk/rack.rb +2 -0
  180. data/lib/clerk/rack_middleware.rb +88 -73
  181. data/lib/clerk/rails.rb +3 -0
  182. data/lib/clerk/railtie.rb +7 -6
  183. data/lib/clerk/sdk.rb +46 -157
  184. data/lib/clerk/sinatra.rb +52 -0
  185. data/lib/clerk/utils.rb +52 -6
  186. data/lib/clerk/version.rb +1 -1
  187. data/lib/clerk.rb +15 -51
  188. metadata +187 -25
  189. data/CODEOWNERS +0 -1
  190. data/lib/clerk/errors.rb +0 -19
  191. data/lib/clerk/rack_middleware_v2.rb +0 -167
  192. data/lib/clerk/resources/allowlist.rb +0 -16
  193. data/lib/clerk/resources/allowlist_identifiers.rb +0 -16
  194. data/lib/clerk/resources/clients.rb +0 -23
  195. data/lib/clerk/resources/email_addresses.rb +0 -17
  196. data/lib/clerk/resources/emails.rb +0 -16
  197. data/lib/clerk/resources/jwks.rb +0 -18
  198. data/lib/clerk/resources/organizations.rb +0 -73
  199. data/lib/clerk/resources/phone_numbers.rb +0 -17
  200. data/lib/clerk/resources/plural_resource.rb +0 -38
  201. data/lib/clerk/resources/sessions.rb +0 -26
  202. data/lib/clerk/resources/singular_resource.rb +0 -14
  203. data/lib/clerk/resources/users.rb +0 -37
  204. data/lib/clerk/resources.rb +0 -10
@@ -0,0 +1,44 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="description" content="Find a domain's name servers">
7
+ <title>Sinatra</title>
8
+ <style>
9
+ html { font-family: monospace; }
10
+ @media (prefers-color-scheme: dark) {
11
+ html {
12
+ color: #FFE6E6FF;
13
+ background-color: #201D1E;
14
+ }
15
+ }
16
+ </style>
17
+ <script
18
+ async
19
+ crossorigin="anonymous"
20
+ data-clerk-publishable-key="<%= Clerk.configuration.publishable_key %>"
21
+ src="<%= ENV["CLERK_JS_URL"] %>"
22
+ type="text/javascript"
23
+ ></script>
24
+ <script>
25
+ window.addEventListener('load', async function () {
26
+ await Clerk.load()
27
+ const container = document.getElementById('auth-container')
28
+
29
+ if (Clerk.user) {
30
+ container.innerHTML = `<div id="user-button"></div>`
31
+ Clerk.mountUserButton(document.getElementById('user-button'))
32
+ } else {
33
+ container.innerHTML = `<div id="sign-in"></div>`
34
+ Clerk.mountSignIn(document.getElementById('sign-in'))
35
+ }
36
+ })
37
+ </script>
38
+ </head>
39
+ <body>
40
+ <h1>Sinatra</h1>
41
+ <h2><%= clerk.user ? "Authenticated User: #{clerk.user.first_name} (#{clerk.user.id}) " : "Not Authenticated" %><h2>
42
+ <div id="auth-container"></div>
43
+ </body>
44
+ </html>
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ["ruby-sdk@clerk.dev"]
10
10
 
11
11
  spec.summary = "Clerk SDK for Ruby."
12
- spec.description = "Client SDK for the Clerk backend API."
12
+ spec.description = "Client SDK for the Clerk"
13
13
  spec.homepage = "https://github.com/clerkinc/clerk-sdk-ruby"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  spec.add_dependency "faraday", ">= 1.4.1", "< 3.0"
31
31
  spec.add_dependency "jwt", '~> 2.5'
32
+ spec.add_dependency "clerk-http-client", "~> 0.0.1"
32
33
  spec.add_dependency "concurrent-ruby", "~> 1.1"
33
34
 
34
35
  spec.add_development_dependency "byebug", "~> 11.1"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/concern"
2
4
 
3
5
  module Clerk
@@ -6,92 +8,25 @@ module Clerk
6
8
 
7
9
  protected
8
10
 
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_verified_session_claims`
14
- # which already contains the verified claims as retrieved from the session
15
- # token.
16
- def 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_verified_session_claims`
24
- # which already contains the verified claims as retrieved from the session
25
- # token.
26
- #
27
- # See https://clerk.com/docs/reference/backend-api/tag/Sessions#operation/VerifySession
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
34
- end
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.
44
- def clerk_user
45
- request.env["clerk"].user
46
- end
47
-
48
- def clerk_user_id
49
- request.env["clerk"].user_id
50
- end
51
-
52
- # Makes a request to the Clerk API to fetch the data of the authenticated
53
- # session's organization. If caching is configured (see
54
- # Config.middleware_cache_store), subsequent calls will return the cached
55
- # object.
56
- def clerk_organization
57
- request.env["clerk"].org
58
- end
59
-
60
- def clerk_organization_id
61
- request.env["clerk"].org_id
62
- end
63
-
64
- def clerk_organization_role
65
- request.env["clerk"].org_role
66
- end
67
-
68
- def clerk_organization_permissions
69
- request.env["clerk"].org_permissions
70
- end
71
-
72
- def clerk_user_signed_in?
73
- !!clerk_verified_session_claims
74
- end
75
-
76
- def clerk_sign_in_url
77
- ENV.fetch("CLERK_SIGN_IN_URL")
11
+ def clerk
12
+ request.env["clerk"]
78
13
  end
79
14
 
80
- def clerk_sign_up_url
81
- ENV.fetch("CLERK_SIGN_UP_URL")
15
+ def require_reverification!(preset = StepUp::Preset::STRICT, &block)
16
+ clerk.user_require_reverification!(preset) do
17
+ return yield(preset) if block_given?
18
+ render_reverification!(preset)
19
+ end
82
20
  end
83
21
 
84
- def clerk_user_profile_url
85
- ENV.fetch("CLERK_USER_PROFILE_URL")
22
+ def render_reverification!(preset = nil)
23
+ render status: 403, json: StepUp::Reverification.error_payload(preset)
86
24
  end
87
25
 
88
26
  included do
89
- helper_method :clerk_session, :clerk_reverify_session!,
90
- :clerk_verified_session_claims, :clerk_verified_session_token,
91
- :clerk_user, :clerk_user_id, :clerk_user_signed_in?, :clerk_sign_in_url,
92
- :clerk_sign_up_url, :clerk_user_profile_url,
93
- :clerk_organization, :clerk_organization_id, :clerk_organization_role,
94
- :clerk_organization_permissions
27
+ if respond_to?(:helper_method)
28
+ helper_method :clerk, :require_reverification!, :render_reverification!
29
+ end
95
30
  end
96
31
  end
97
32
  end
@@ -1,183 +1,168 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "ostruct"
2
4
  require "forwardable"
3
- require "base64"
4
5
 
5
6
  module Clerk
6
- ##
7
- # This class represents a parameter object used to contain all request and configuration
8
- # information required by the middleware to resolve the current request state.
9
- # link: https://refactoring.guru/introduce-parameter-object
10
- class AuthenticateContext
11
- extend Forwardable
12
-
13
- ##
14
- # Expose the url of the request that this parameter object was created from as a URI object.
15
- attr_reader :clerk_url
16
-
17
- ##
18
- # Expose properties that does not require validations or complex logic to retrieve
19
- # values by delegating them to the cookies or headers variables.
20
- def_delegators :@cookies, :session_token_in_cookie, :client_uat
21
- def_delegators :@headers, :session_token_in_header, :sec_fetch_dest
22
-
23
- ##
24
- # Creates a new parameter object using Rack::Request and Clerk::Config objects.
25
- def initialize(request, config)
26
- @clerk_url = URI.parse(request.url)
27
- @config = config
28
-
29
- @cookies = OpenStruct.new({
30
- session_token_in_cookie: request.cookies[SESSION_COOKIE],
31
- client_uat: request.cookies[CLIENT_UAT_COOKIE],
32
- handshake_token: request.cookies[HANDSHAKE_COOKIE],
33
- dev_browser: request.cookies[DEV_BROWSER_COOKIE]
34
- })
35
-
36
- @headers = OpenStruct.new({
37
- session_token_in_header: request.env[AUTHORIZATION_HEADER].to_s.gsub(/bearer/i, '').strip,
38
- sec_fetch_dest: request.env[SEC_FETCH_DEST_HEADER],
39
- accept: request.env[ACCEPT_HEADER].to_s,
40
- origin: request.env[ORIGIN_HEADER].to_s,
41
- host: request.host,
42
- port: request.port
43
- })
44
- end
45
-
46
- ##
47
- # The following properties are part of the props supported in all the AuthenticateContext
48
- # objects across all of our SDKs (eg JS, Go)
49
- def secret_key
50
- @config.api_key.to_s
51
- end
52
-
53
- def publishable_key
54
- @config.publishable_key.to_s
55
- end
56
-
57
- def domain
58
- # TODO(dimkl): Add multi-domain support
59
- ""
60
- end
61
-
62
- def is_satellite?
63
- # TODO(dimkl): Add multi-domain support
64
- false
65
- end
66
-
67
- def proxy_url
68
- # TODO(dimkl): Add multi-domain support
69
- ""
70
- end
71
-
72
- def handshake_token
73
- @handshake_token ||= retrieve_from_query_string(@clerk_url, HANDSHAKE_COOKIE) || @cookies.handshake_token.to_s
74
- end
75
-
76
- def clerk_synced?
77
- # TODO(dimkl): Add multi-domain support
78
- false
79
- end
80
-
81
- def clerk_redirect_url
82
- # TODO(dimkl): Add multi-domain support
83
- ""
84
- end
85
-
86
- def dev_browser
87
- @dev_browser ||= retrieve_from_query_string(@clerk_url, DEV_BROWSER_COOKIE) || @cookies.dev_browser.to_s
88
- end
89
-
90
- # The frontend_api returned is without protocol prefix
91
- def frontend_api
92
- return "" if !valid_publishable_key?(publishable_key.to_s)
93
-
94
- @frontend_api ||= if !proxy_url.empty?
95
- proxy_url
96
- elsif development_instance? && !domain.empty?
97
- "clerk.#{domain}"
98
- else
99
- # remove $ postfix
100
- decode_publishable_key(publishable_key).chop
101
- end
102
- end
103
-
104
- def development_instance?
105
- secret_key.start_with?("sk_test_")
106
- end
107
-
108
- def production_instance?
109
- secret_key.start_with?("sk_live_")
110
- end
111
-
112
- def document_request?
113
- @headers.sec_fetch_dest == "document"
114
- end
115
-
116
- def accepts_html?
117
- @headers.accept && @headers.accept.start_with?('text/html')
118
- end
119
-
120
- def eligible_for_multi_domain?
121
- is_satellite? && document_request? && !clerk_synced?
122
- end
123
-
124
- def active_client?
125
- @cookies.client_uat.to_i > 0
126
- end
127
-
128
- def cross_origin_request?
129
- # origin contains scheme+host and optionally port (omitted if 80 or 443)
130
- # ref. https://www.rfc-editor.org/rfc/rfc6454#section-6.1
131
- return false if @headers.origin.nil?
132
-
133
- # strip scheme
134
- origin = @headers.origin.strip.sub(/\A(\w+:)?\/\//, '')
135
- return false if origin.empty?
136
-
137
- # Rack's host and port helpers are reverse-proxy-aware; that
138
- # is, they prefer the de-facto X-Forwarded-* headers if they're set
139
- request_host = @headers.host
140
- request_host << ":#{@headers.port}" if @headers.port != 80 && @headers.port != 443
141
-
142
- origin != request_host
143
- end
144
-
145
- def dev_browser?
146
- !dev_browser.empty?
147
- end
148
-
149
- def session_token_in_header?
150
- !session_token_in_header.to_s.empty?
151
- end
152
-
153
- def handshake_token?
154
- !handshake_token.to_s.empty?
155
- end
156
-
157
- def session_token_in_cookie?
158
- !session_token_in_cookie.to_s.empty?
159
- end
160
-
161
- private
162
-
163
- def valid_publishable_key?(pk)
164
- valid_publishable_key_prefix?(pk) && valid_publishable_key_postfix?(pk)
165
- end
166
-
167
- def valid_publishable_key_prefix?(pk)
168
- pk.start_with?("pk_live_") || pk.start_with?("pk_test_")
169
- end
170
-
171
- def valid_publishable_key_postfix?(pk)
172
- decode_publishable_key(pk).end_with?("$")
173
- end
174
-
175
- def decode_publishable_key(pk)
176
- Base64.decode64(pk.split("_")[2].to_s)
177
- end
178
-
179
- def retrieve_from_query_string(url, key)
180
- Rack::Utils.parse_query(url.query)[key]
181
- end
182
- end
183
- end
7
+ # This class represents a parameter object used to contain all request and configuration
8
+ # information required by the middleware to resolve the current request state.
9
+ # link: https://refactoring.guru/introduce-parameter-object
10
+ class AuthenticateContext
11
+ extend Forwardable
12
+
13
+ # Expose the url of the request that this parameter object was created from as a URI object.
14
+ attr_reader :clerk_url
15
+
16
+ # Expose properties that does not require validations or complex logic to retrieve
17
+ # values by delegating them to the cookies or headers variables.
18
+ def_delegators :@cookies, :session_token_in_cookie, :client_uat
19
+ def_delegators :@headers, :session_token_in_header, :sec_fetch_dest
20
+
21
+ # Creates a new parameter object using ::Rack::Request and Clerk::Config objects.
22
+ def initialize(request, config)
23
+ @clerk_url = URI.parse(request.url)
24
+ @config = config
25
+
26
+ @cookies = OpenStruct.new({
27
+ client_uat: request.cookies[CLIENT_UAT_COOKIE],
28
+ dev_browser: request.cookies[DEV_BROWSER_COOKIE],
29
+ handshake_token: request.cookies[HANDSHAKE_COOKIE],
30
+ session_token_in_cookie: request.cookies[SESSION_COOKIE]
31
+ })
32
+
33
+ @headers = OpenStruct.new({
34
+ accept: request.env[ACCEPT_HEADER].to_s,
35
+ host: request.host,
36
+ origin: request.env[ORIGIN_HEADER].to_s,
37
+ port: request.port,
38
+ sec_fetch_dest: request.env[SEC_FETCH_DEST_HEADER],
39
+ session_token_in_header: request.env[AUTHORIZATION_HEADER].to_s.gsub(/bearer/i, "").strip
40
+ })
41
+ end
42
+
43
+ # The following properties are part of the props supported in all the AuthenticateContext
44
+ # objects across all of our SDKs (eg JS, Go)
45
+ def secret_key
46
+ raise ConfigurationError, "Clerk secret key is not set" if @config.secret_key.to_s.empty?
47
+
48
+ @config.secret_key.to_s
49
+ end
50
+
51
+ def publishable_key
52
+ raise ConfigurationError, "Clerk publishable key is not set" if @config.publishable_key.to_s.to_s.empty?
53
+
54
+ @config.publishable_key.to_s
55
+ end
56
+
57
+ def proxy_url?
58
+ !proxy_url.empty?
59
+ end
60
+
61
+ def handshake_token
62
+ @handshake_token ||= Utils.retrieve_from_query_string(@clerk_url, HANDSHAKE_COOKIE) || @cookies.handshake_token.to_s
63
+ end
64
+
65
+ def dev_browser
66
+ @dev_browser ||= dev_browser_in_url || @cookies.dev_browser.to_s
67
+ end
68
+
69
+ # The frontend_api returned is without protocol prefix
70
+ def frontend_api
71
+ return "" unless Utils.valid_publishable_key?(publishable_key.to_s)
72
+
73
+ @frontend_api ||= if proxy_url?
74
+ proxy_url
75
+ elsif development_instance? && !domain.empty?
76
+ "clerk.#{domain}"
77
+ else
78
+ # remove $ postfix
79
+ Utils.decode_publishable_key(publishable_key).chop.to_s
80
+ end
81
+ end
82
+
83
+ def development_instance?
84
+ secret_key.start_with?("sk_test_")
85
+ end
86
+
87
+ def production_instance?
88
+ secret_key.start_with?("sk_live_")
89
+ end
90
+
91
+ def document_request?
92
+ @headers.sec_fetch_dest == "document"
93
+ end
94
+
95
+ def accepts_html?
96
+ @headers.accept&.start_with?("text/html")
97
+ end
98
+
99
+ def eligible_for_multi_domain?
100
+ is_satellite? && document_request? && !clerk_synced?
101
+ end
102
+
103
+ def active_client?
104
+ @cookies.client_uat.to_i.positive?
105
+ end
106
+
107
+ def cross_origin_request?
108
+ # origin contains scheme+host and optionally port (omitted if 80 or 443)
109
+ # ref. https://www.rfc-editor.org/rfc/rfc6454#section-6.1
110
+ return false if @headers.origin.nil?
111
+
112
+ # strip scheme
113
+ origin = @headers.origin.strip.sub(%r{\A(\w+:)?//}, "")
114
+ return false if origin.empty?
115
+
116
+ # Rack's host and port helpers are reverse-proxy-aware; that
117
+ # is, they prefer the de-facto X-Forwarded-* headers if they're set
118
+ request_host = @headers.host
119
+ request_host << ":#{@headers.port}" if @headers.port != 80 && @headers.port != 443
120
+
121
+ origin != request_host
122
+ end
123
+
124
+ def dev_browser?
125
+ !dev_browser.empty?
126
+ end
127
+
128
+ def session_token_in_header?
129
+ !session_token_in_header.to_s.empty?
130
+ end
131
+
132
+ def handshake_token?
133
+ !handshake_token.to_s.empty?
134
+ end
135
+
136
+ def session_token_in_cookie?
137
+ !session_token_in_cookie.to_s.empty?
138
+ end
139
+
140
+ def dev_browser_in_url
141
+ Utils.retrieve_from_query_string(@clerk_url, DEV_BROWSER_COOKIE)
142
+ end
143
+
144
+ def dev_browser_in_url?
145
+ !!dev_browser_in_url
146
+ end
147
+
148
+ def domain
149
+ "" # TODO: Add multi-domain support
150
+ end
151
+
152
+ def is_satellite?
153
+ false # TODO: Add multi-domain support
154
+ end
155
+
156
+ def proxy_url
157
+ "" # TODO: Add multi-domain support
158
+ end
159
+
160
+ def clerk_synced?
161
+ false # TODO: Add multi-domain support
162
+ end
163
+
164
+ def clerk_redirect_url
165
+ "" # TODO: Add multi-domain support
166
+ end
167
+ end
168
+ end