th7-clerk-sdk-ruby 4.2.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 +7 -0
- data/.env.example +3 -0
- data/.github/workflows/main.yml +30 -0
- data/.github/workflows/semgrep.yml +24 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +212 -0
- data/Gemfile +33 -0
- data/Gemfile.lock +300 -0
- data/Guardfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +278 -0
- data/Rakefile +56 -0
- data/apps/rack/app.rb +67 -0
- data/apps/rack/config.ru +17 -0
- data/apps/rack/middleware/disable_paths.rb +13 -0
- data/apps/rails-api/.dockerignore +41 -0
- data/apps/rails-api/.gitattributes +9 -0
- data/apps/rails-api/.gitignore +32 -0
- data/apps/rails-api/.kamal/hooks/docker-setup.sample +3 -0
- data/apps/rails-api/.kamal/hooks/post-deploy.sample +14 -0
- data/apps/rails-api/.kamal/hooks/post-proxy-reboot.sample +3 -0
- data/apps/rails-api/.kamal/hooks/pre-build.sample +51 -0
- data/apps/rails-api/.kamal/hooks/pre-connect.sample +47 -0
- data/apps/rails-api/.kamal/hooks/pre-deploy.sample +109 -0
- data/apps/rails-api/.kamal/hooks/pre-proxy-reboot.sample +3 -0
- data/apps/rails-api/.kamal/secrets +17 -0
- data/apps/rails-api/.rubocop.yml +8 -0
- data/apps/rails-api/.ruby-version +1 -0
- data/apps/rails-api/Dockerfile +69 -0
- data/apps/rails-api/Gemfile +54 -0
- data/apps/rails-api/Gemfile.lock +374 -0
- data/apps/rails-api/README.md +24 -0
- data/apps/rails-api/Rakefile +6 -0
- data/apps/rails-api/app/controllers/application_controller.rb +3 -0
- data/apps/rails-api/app/controllers/home_controller.rb +5 -0
- data/apps/rails-api/app/jobs/application_job.rb +7 -0
- data/apps/rails-api/app/mailers/application_mailer.rb +4 -0
- data/apps/rails-api/app/models/application_record.rb +3 -0
- data/apps/rails-api/app/views/layouts/mailer.html.erb +13 -0
- data/apps/rails-api/app/views/layouts/mailer.text.erb +1 -0
- data/apps/rails-api/bin/brakeman +7 -0
- data/apps/rails-api/bin/bundle +109 -0
- data/apps/rails-api/bin/dev +2 -0
- data/apps/rails-api/bin/docker-entrypoint +14 -0
- data/apps/rails-api/bin/jobs +6 -0
- data/apps/rails-api/bin/kamal +27 -0
- data/apps/rails-api/bin/rails +4 -0
- data/apps/rails-api/bin/rake +4 -0
- data/apps/rails-api/bin/rubocop +8 -0
- data/apps/rails-api/bin/setup +34 -0
- data/apps/rails-api/bin/thrust +5 -0
- data/apps/rails-api/config/application.rb +36 -0
- data/apps/rails-api/config/boot.rb +4 -0
- data/apps/rails-api/config/cable.yml +17 -0
- data/apps/rails-api/config/cache.yml +16 -0
- data/apps/rails-api/config/credentials.yml.enc +1 -0
- data/apps/rails-api/config/database.yml +41 -0
- data/apps/rails-api/config/deploy.yml +116 -0
- data/apps/rails-api/config/environment.rb +5 -0
- data/apps/rails-api/config/environments/development.rb +70 -0
- data/apps/rails-api/config/environments/production.rb +88 -0
- data/apps/rails-api/config/environments/test.rb +53 -0
- data/apps/rails-api/config/initializers/cors.rb +16 -0
- data/apps/rails-api/config/initializers/filter_parameter_logging.rb +8 -0
- data/apps/rails-api/config/initializers/inflections.rb +16 -0
- data/apps/rails-api/config/locales/en.yml +31 -0
- data/apps/rails-api/config/puma.rb +41 -0
- data/apps/rails-api/config/queue.yml +18 -0
- data/apps/rails-api/config/recurring.yml +10 -0
- data/apps/rails-api/config/routes.rb +10 -0
- data/apps/rails-api/config/storage.yml +34 -0
- data/apps/rails-api/config.ru +6 -0
- data/apps/rails-api/db/cable_schema.rb +11 -0
- data/apps/rails-api/db/cache_schema.rb +14 -0
- data/apps/rails-api/db/queue_schema.rb +129 -0
- data/apps/rails-api/db/seeds.rb +9 -0
- data/apps/rails-api/public/robots.txt +1 -0
- data/apps/rails-api/test/controllers/home_controller_test.rb +7 -0
- data/apps/rails-api/test/test_helper.rb +15 -0
- data/apps/rails-full/.dockerignore +47 -0
- data/apps/rails-full/.gitattributes +9 -0
- data/apps/rails-full/.gitignore +34 -0
- data/apps/rails-full/.kamal/hooks/docker-setup.sample +3 -0
- data/apps/rails-full/.kamal/hooks/post-deploy.sample +14 -0
- data/apps/rails-full/.kamal/hooks/post-proxy-reboot.sample +3 -0
- data/apps/rails-full/.kamal/hooks/pre-build.sample +51 -0
- data/apps/rails-full/.kamal/hooks/pre-connect.sample +47 -0
- data/apps/rails-full/.kamal/hooks/pre-deploy.sample +109 -0
- data/apps/rails-full/.kamal/hooks/pre-proxy-reboot.sample +3 -0
- data/apps/rails-full/.kamal/secrets +17 -0
- data/apps/rails-full/.rubocop.yml +8 -0
- data/apps/rails-full/.ruby-version +1 -0
- data/apps/rails-full/Dockerfile +72 -0
- data/apps/rails-full/Gemfile +70 -0
- data/apps/rails-full/Gemfile.lock +429 -0
- data/apps/rails-full/README.md +24 -0
- data/apps/rails-full/Rakefile +6 -0
- data/apps/rails-full/app/assets/stylesheets/application.css +10 -0
- data/apps/rails-full/app/controllers/application_controller.rb +6 -0
- data/apps/rails-full/app/controllers/home_controller.rb +11 -0
- data/apps/rails-full/app/helpers/application_helper.rb +2 -0
- data/apps/rails-full/app/helpers/home_helper.rb +2 -0
- data/apps/rails-full/app/javascript/application.js +3 -0
- data/apps/rails-full/app/javascript/controllers/application.js +9 -0
- data/apps/rails-full/app/javascript/controllers/hello_controller.js +7 -0
- data/apps/rails-full/app/javascript/controllers/index.js +4 -0
- data/apps/rails-full/app/jobs/application_job.rb +7 -0
- data/apps/rails-full/app/mailers/application_mailer.rb +4 -0
- data/apps/rails-full/app/models/application_record.rb +3 -0
- data/apps/rails-full/app/views/home/index.html.erb +7 -0
- data/apps/rails-full/app/views/layouts/application.html.erb +60 -0
- data/apps/rails-full/app/views/layouts/mailer.html.erb +13 -0
- data/apps/rails-full/app/views/layouts/mailer.text.erb +1 -0
- data/apps/rails-full/app/views/pwa/manifest.json.erb +22 -0
- data/apps/rails-full/app/views/pwa/service-worker.js +26 -0
- data/apps/rails-full/bin/brakeman +7 -0
- data/apps/rails-full/bin/bundle +109 -0
- data/apps/rails-full/bin/dev +2 -0
- data/apps/rails-full/bin/docker-entrypoint +14 -0
- data/apps/rails-full/bin/importmap +4 -0
- data/apps/rails-full/bin/jobs +6 -0
- data/apps/rails-full/bin/kamal +27 -0
- data/apps/rails-full/bin/rails +4 -0
- data/apps/rails-full/bin/rake +4 -0
- data/apps/rails-full/bin/rubocop +8 -0
- data/apps/rails-full/bin/setup +34 -0
- data/apps/rails-full/bin/thrust +5 -0
- data/apps/rails-full/config/application.rb +31 -0
- data/apps/rails-full/config/boot.rb +4 -0
- data/apps/rails-full/config/cable.yml +17 -0
- data/apps/rails-full/config/cache.yml +16 -0
- data/apps/rails-full/config/credentials.yml.enc +1 -0
- data/apps/rails-full/config/database.yml +41 -0
- data/apps/rails-full/config/deploy.yml +116 -0
- data/apps/rails-full/config/environment.rb +5 -0
- data/apps/rails-full/config/environments/development.rb +72 -0
- data/apps/rails-full/config/environments/production.rb +91 -0
- data/apps/rails-full/config/environments/test.rb +53 -0
- data/apps/rails-full/config/importmap.rb +7 -0
- data/apps/rails-full/config/initializers/assets.rb +7 -0
- data/apps/rails-full/config/initializers/clerk.rb +4 -0
- data/apps/rails-full/config/initializers/content_security_policy.rb +25 -0
- data/apps/rails-full/config/initializers/filter_parameter_logging.rb +8 -0
- data/apps/rails-full/config/initializers/inflections.rb +16 -0
- data/apps/rails-full/config/locales/en.yml +31 -0
- data/apps/rails-full/config/puma.rb +41 -0
- data/apps/rails-full/config/queue.yml +18 -0
- data/apps/rails-full/config/recurring.yml +10 -0
- data/apps/rails-full/config/routes.rb +15 -0
- data/apps/rails-full/config/storage.yml +34 -0
- data/apps/rails-full/config.ru +6 -0
- data/apps/rails-full/db/cable_schema.rb +11 -0
- data/apps/rails-full/db/cache_schema.rb +14 -0
- data/apps/rails-full/db/queue_schema.rb +129 -0
- data/apps/rails-full/db/seeds.rb +9 -0
- data/apps/rails-full/public/400.html +114 -0
- data/apps/rails-full/public/404.html +114 -0
- data/apps/rails-full/public/406-unsupported-browser.html +114 -0
- data/apps/rails-full/public/422.html +114 -0
- data/apps/rails-full/public/500.html +114 -0
- data/apps/rails-full/public/icon.png +0 -0
- data/apps/rails-full/public/icon.svg +3 -0
- data/apps/rails-full/public/robots.txt +1 -0
- data/apps/rails-full/test/application_system_test_case.rb +5 -0
- data/apps/rails-full/test/controllers/home_controller_test.rb +7 -0
- data/apps/rails-full/test/test_helper.rb +15 -0
- data/apps/sinatra/app.rb +29 -0
- data/apps/sinatra/config.ru +8 -0
- data/apps/sinatra/views/index.erb +44 -0
- data/bin/console +16 -0
- data/bin/release +21 -0
- data/bin/setup +8 -0
- data/clerk-sdk-ruby.gemspec +38 -0
- data/docs/clerk-logo-dark.png +0 -0
- data/docs/clerk-logo-light.png +0 -0
- data/lib/clerk/authenticatable.rb +32 -0
- data/lib/clerk/authenticate_context.rb +168 -0
- data/lib/clerk/authenticate_request.rb +261 -0
- data/lib/clerk/configuration.rb +84 -0
- data/lib/clerk/constants.rb +74 -0
- data/lib/clerk/error.rb +17 -0
- data/lib/clerk/jwks_cache.rb +37 -0
- data/lib/clerk/proxy.rb +135 -0
- data/lib/clerk/rack.rb +2 -0
- data/lib/clerk/rack_middleware.rb +112 -0
- data/lib/clerk/rails.rb +3 -0
- data/lib/clerk/railtie.rb +15 -0
- data/lib/clerk/sdk.rb +84 -0
- data/lib/clerk/sinatra.rb +52 -0
- data/lib/clerk/utils.rb +73 -0
- data/lib/clerk/version.rb +5 -0
- data/lib/clerk.rb +27 -0
- metadata +340 -0
data/README.md
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<a href="https://www.clerk.com/?utm_source=github&utm_medium=starter_repos&utm_campaign=sdk_ruby" target="_blank" align="center">
|
3
|
+
<picture>
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="./docs/clerk-logo-dark.png">
|
5
|
+
<img src="./docs/clerk-logo-light.png" height="64">
|
6
|
+
</picture>
|
7
|
+
</a>
|
8
|
+
<br />
|
9
|
+
</p>
|
10
|
+
|
11
|
+
# Clerk Ruby SDK
|
12
|
+
|
13
|
+
This SDK allows you to call the [Clerk](https://www.clerk.com/?utm_source=github&utm_medium=starter_repos&utm_campaign=sdk_ruby) Backend API from Ruby code without having to implement the calls yourself.
|
14
|
+
|
15
|
+
[](https://discord.com/invite/b5rXHjAg7A)
|
16
|
+
[](https://clerk.com/docs)
|
17
|
+
[](https://twitter.com/intent/follow?screen_name=ClerkDev)
|
18
|
+
|
19
|
+
---
|
20
|
+
|
21
|
+
**Clerk is Hiring!**
|
22
|
+
|
23
|
+
Would you like to work on Open Source software and help maintain this repository? [Apply today!](https://apply.workable.com/clerk-dev/)
|
24
|
+
|
25
|
+
---
|
26
|
+
|
27
|
+
**Note**: You're looking at the main branch, which requires that you use [Auth
|
28
|
+
v2](https://clerk.com/docs/upgrade-guides/auth-v2).
|
29
|
+
|
30
|
+
If you're looking for the legacy authentication scheme, refer to the
|
31
|
+
[`v1`](https://github.com/clerkinc/clerk-sdk-ruby/tree/v1) branch.
|
32
|
+
|
33
|
+
## Installation
|
34
|
+
|
35
|
+
Add this line to your application's Gemfile:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
gem 'clerk-sdk-ruby', require: "clerk"
|
39
|
+
```
|
40
|
+
|
41
|
+
And then execute:
|
42
|
+
|
43
|
+
$ bundle install
|
44
|
+
|
45
|
+
Or install it yourself as:
|
46
|
+
|
47
|
+
$ gem install clerk-sdk-ruby
|
48
|
+
|
49
|
+
## Quick Start
|
50
|
+
|
51
|
+
First, you need to get an API key for a Clerk instance. This is done via the
|
52
|
+
[Clerk dashboard](https://dashboard.clerk.com/applications).
|
53
|
+
|
54
|
+
Then you can instantiate a `Clerk::SDK` instance and access all
|
55
|
+
[Backend API](https://clerk.com/docs/reference/backend-api) endpoints.
|
56
|
+
Here's a quick example:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
clerk = Clerk::SDK.new(api_key: "your_api_key")
|
60
|
+
# List all users
|
61
|
+
clerk.users.get_user_list
|
62
|
+
# Get your first user
|
63
|
+
user = clerk.users.get_user_list(limit: 1).first
|
64
|
+
# Extract their primary email address ID
|
65
|
+
email_id = user["primary_email_address_id"]
|
66
|
+
|
67
|
+
# Create an organization
|
68
|
+
p Clerk::SDK.organizations.create_organization({
|
69
|
+
create_organization_request: ClerkHttpClient::CreateOrganizationRequest.new({
|
70
|
+
name: 'example'
|
71
|
+
})
|
72
|
+
})
|
73
|
+
```
|
74
|
+
|
75
|
+
## Configuration
|
76
|
+
|
77
|
+
The SDK can be configured in three ways: environment variables, configuration
|
78
|
+
singleton and constructor arguments. The priority goes like this:
|
79
|
+
|
80
|
+
1. Constructor arguments
|
81
|
+
2. Configuration object
|
82
|
+
3. Environment variables
|
83
|
+
|
84
|
+
If an argument is not provided, the configuration object is looked up, which
|
85
|
+
falls back to the associated environment variable. Here's an example with all
|
86
|
+
supported configuration settings their environment variable equivalents:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
Clerk.configure do |c|
|
90
|
+
c.secret_key = "sk_(test|live)_...." # if omitted: ENV["CLERK_SECRET_KEY"] - API calls will fail if unset
|
91
|
+
c.publishable_key = "pk_(test|live)_...." # if omitted: ENV["CLERK_PUBLISHABLE_KEY"] - Handshake mechanism (check section below) will fail if unset
|
92
|
+
c.logger = Logger.new(STDOUT) # if omitted, no logging
|
93
|
+
c.middleware_cache_store = ActiveSupport::Cache::FileStore.new("/tmp/clerk_middleware_cache") # if omitted: no caching
|
94
|
+
c.excluded_routes ["/foo", "/bar/*"]
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
You can customize each instance of the `Clerk::SDK` object by passing keyword
|
99
|
+
arguments to the constructor:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
clerk = Clerk::SDK.new(
|
103
|
+
logger: Logger.new()
|
104
|
+
secret_key: "X",
|
105
|
+
)
|
106
|
+
```
|
107
|
+
|
108
|
+
For full customization, you can instead pass a `Faraday` object directly, which
|
109
|
+
will ignore all the other arguments, if passed:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
faraday = Faraday.new()
|
113
|
+
clerk = Clerk::SDK.new(connection: faraday)
|
114
|
+
```
|
115
|
+
|
116
|
+
Refer to the [Faraday documentation](https://lostisland.github.io/faraday/usage/#customizing-faradayconnection)
|
117
|
+
for details.
|
118
|
+
|
119
|
+
## Rack middleware
|
120
|
+
|
121
|
+
The SDK comes with a Rack middleware which lazily loads the Clerk session and
|
122
|
+
user. It inserts a `clerk` key in the Rack environment, which is an instance
|
123
|
+
of `Clerk::Proxy`. To get the session or the user of the session, you call
|
124
|
+
`session` or `user` respectively. In case there is no session, you can retrieve
|
125
|
+
the API error with the `error` getter method.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
use Clerk::Rack::Middleware
|
129
|
+
```
|
130
|
+
|
131
|
+
### Reverification middleware
|
132
|
+
|
133
|
+
The SDK comes with a revalidation middleware which will automatically revalidate the session when the user navigates to a protected route.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
use Clerk::Rack::Reverification,
|
137
|
+
preset: Clerk::StepUp::Preset::LAX,
|
138
|
+
routes: ["/*"]
|
139
|
+
```
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
## Rails integration
|
144
|
+
|
145
|
+
The SDK will automatically add the [Rack middleware](#rack-middleware) to the
|
146
|
+
middleware stack. For easier access to the Clerk session and user, include the
|
147
|
+
`Clerk::Authenticatable` concern in your controller:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
class ApplicationController < ActionController::Base
|
151
|
+
include Clerk::Authenticatable
|
152
|
+
end
|
153
|
+
|
154
|
+
class AdminController < ApplicationController
|
155
|
+
before_action :require_reverification!, only: [:protected]
|
156
|
+
|
157
|
+
def index
|
158
|
+
@user = clerk.user
|
159
|
+
end
|
160
|
+
|
161
|
+
def protected
|
162
|
+
render json: {message: clerk.user? ? "Valid session" : "Not logged in"}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
This gives your controller and views access to the following methods and more:
|
168
|
+
|
169
|
+
- `clerk.sdk.*`
|
170
|
+
- `clerk.user?`
|
171
|
+
- `clerk.user`: NOTE: This makes an additional request and attempts to cache it.
|
172
|
+
- `clerk.user_id`
|
173
|
+
- `clerk.organization?`
|
174
|
+
- `clerk.organization` NOTE: This makes an additional request and attempts to cache it.
|
175
|
+
- `clerk.organization_id`
|
176
|
+
- `clerk.organization_role`
|
177
|
+
- `clerk.organization_permissions`
|
178
|
+
|
179
|
+
### Skipping the Railtie
|
180
|
+
|
181
|
+
There are cases where you might not want to use the Railtie, for example, only using the SDK in a Rails application. To accomplish this, you can set the `CLERK_SKIP_RAILTIE` environment variable to `true`.
|
182
|
+
|
183
|
+
This will prevent the Railtie from being loaded and the Rack middleware from being added to the middleware stack.
|
184
|
+
|
185
|
+
You can still configure the SDK as normal, but you will need to call the SDK using `Clerk::SDK.new` instead of the `clerk.sdk` helper.
|
186
|
+
|
187
|
+
## Sinatra integration
|
188
|
+
|
189
|
+
The SDK enables the use of Extensions to add Clerk support to your Sinatra application.
|
190
|
+
|
191
|
+
`Sinatra::Clerk` will automatically add the [Rack middleware](#rack-middleware)to the
|
192
|
+
middleware stack and enable easy access to the Clerk session and user helper methods.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
class App < Sinatra::Base
|
196
|
+
register Sinatra::Clerk
|
197
|
+
|
198
|
+
get "/" do
|
199
|
+
erb :index, format: :html5
|
200
|
+
end
|
201
|
+
|
202
|
+
get "/admin" do
|
203
|
+
@user = clerk.user
|
204
|
+
erb :index, format: :html5
|
205
|
+
end
|
206
|
+
|
207
|
+
get "/protected" do
|
208
|
+
require_reverification!
|
209
|
+
{message: clerk.user? ? "Valid session" : "Not logged in"}.to_json
|
210
|
+
end
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
## Internals
|
215
|
+
|
216
|
+
The API client depends on the excellent [Faraday](https://rubygems.org/gems/faraday)
|
217
|
+
gem for HTTP requests. You can swap out the original implementation with your
|
218
|
+
own customized instance.
|
219
|
+
|
220
|
+
The API client sends all requests as `application/x-www-form-urlencoded`. The
|
221
|
+
API then responds with JSON which is then converted and returned as a Ruby
|
222
|
+
`Hash`, or `Array` of hashes. Errors are also returned as a JSON object, with a
|
223
|
+
single key (`errors`) containing an array of error objects.
|
224
|
+
|
225
|
+
Read the [API documentation](https://clerk.com/docs/reference/backend-api)
|
226
|
+
for details on expected parameters and response formats.
|
227
|
+
|
228
|
+
<a name="handshake"></a>
|
229
|
+
|
230
|
+
### Handshake
|
231
|
+
|
232
|
+
The Client Handshake is a mechanism that is used to resolve a request’s authentication state from “unknown” to definitively signed in or signed out. Clerk’s session management architecture relies on a short-lived session JWT to validate requests, along with a long-lived session that is used to keep the session JWT fresh by interacting with the Frontend API. The long-lived session token is stored in an HttpOnly cookie associated with the Frontend API domain. If a short-lived session JWT is expired on a request to an application’s backend, the SDK doesn’t know if the session has ended, or if a new short-lived JWT needs to be issued. When an SDK gets into this state, it triggers the handshake.
|
233
|
+
|
234
|
+
With the handshake, we can resolve the authentication state on the backend and ensure the request is properly handled as signed in or out, instead of being in a potentially “unknown” state. The handshake flow relies on redirects to exchange session information between FAPI and the application, ensuring the resolution of unknown authentication states minimizes performance impact and behaves consistently across different framework and language implementations.
|
235
|
+
|
236
|
+
## Development
|
237
|
+
|
238
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
239
|
+
`bundle exec rake spec` to run the tests. You can also run `bin/console` for an
|
240
|
+
interactive prompt that will allow you to experiment.
|
241
|
+
|
242
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
243
|
+
|
244
|
+
To run the example applications, run:
|
245
|
+
|
246
|
+
```bash
|
247
|
+
rake app:rack
|
248
|
+
rake app:rails
|
249
|
+
rake app:rails:api
|
250
|
+
rake app:sinatra
|
251
|
+
```
|
252
|
+
|
253
|
+
## Release
|
254
|
+
|
255
|
+
To release a new version:
|
256
|
+
- update the version number in `version.rb`
|
257
|
+
- update `CHANGELOG.md` to include information about the changes
|
258
|
+
- merge changes into main
|
259
|
+
- run `bundle exec rake release`
|
260
|
+
|
261
|
+
If gem publishing is NOT executed automatically:
|
262
|
+
- run `gem push pkg/clerk-sdk-ruby-{version}.gem` to push the `.gem` file to [rubygems.org](https://rubygems.org)
|
263
|
+
|
264
|
+
The `bundle exec rake release` command:
|
265
|
+
- creates a git tag with the version found in `version.rb`
|
266
|
+
- pushes the git tag
|
267
|
+
|
268
|
+
## Yank release
|
269
|
+
|
270
|
+
We should avoid yanking a releasing but if it's necessary execute `gem yank clerk-sdk-ruby -v {version}`
|
271
|
+
|
272
|
+
## Contributing
|
273
|
+
|
274
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/clerkinc/clerk-sdk-ruby.
|
275
|
+
|
276
|
+
## License
|
277
|
+
|
278
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "standard/rake"
|
5
|
+
|
6
|
+
################################
|
7
|
+
# COVERAGE
|
8
|
+
################################
|
9
|
+
|
10
|
+
desc "Open coverage report"
|
11
|
+
task(:cov) { system "open coverage/index.html" }
|
12
|
+
|
13
|
+
################################
|
14
|
+
# TESTING
|
15
|
+
################################
|
16
|
+
|
17
|
+
desc "Run all tests"
|
18
|
+
task spec: "spec:all"
|
19
|
+
|
20
|
+
namespace :spec do
|
21
|
+
task(:all) { system "bundle exec rspec" }
|
22
|
+
|
23
|
+
desc "Run tests on file changes"
|
24
|
+
task(:watch) { system "bundle exec guard -g spec" }
|
25
|
+
|
26
|
+
desc "Run failed tests only"
|
27
|
+
task(:failed) { system "bundle exec rspec --only-failures" }
|
28
|
+
end
|
29
|
+
|
30
|
+
################################
|
31
|
+
# PLAYGROUND APPLICATIONS
|
32
|
+
################################
|
33
|
+
|
34
|
+
namespace :app do
|
35
|
+
desc "Run Rails (full stack) application"
|
36
|
+
task rails: "rails:full"
|
37
|
+
|
38
|
+
namespace :rails do
|
39
|
+
task :full do
|
40
|
+
cd ("apps/rails-full") { system "bin/rails server" }
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Run Rails (API only) application"
|
44
|
+
task :api do
|
45
|
+
cd ("apps/rails-api") { system "bin/rails server" }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Run Rack application"
|
50
|
+
task(:rack) { system "rerun --dir lib,apps/rack --pattern '**/*.{rb,ru}' -- bundle exec puma apps/rack/config.ru -p 3000" }
|
51
|
+
|
52
|
+
desc "Run Sinatra application"
|
53
|
+
task(:sinatra) { system "rerun --dir lib,apps/sinatra --pattern '**/*.{erb,rb,ru}' -- bundle exec puma apps/sinatra/config.ru -p 3000 -v" }
|
54
|
+
end
|
55
|
+
|
56
|
+
|
data/apps/rack/app.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "clerk"
|
3
|
+
|
4
|
+
class App
|
5
|
+
def call(env)
|
6
|
+
# # Example: Without using `Clerk::Rack::Reverification` Middleware
|
7
|
+
# preset = Clerk::StepUp::Preset::LAX
|
8
|
+
# if env["clerk"].user_needs_reverification?(preset)
|
9
|
+
# return env["clerk"].user_reverification_rack_response(preset)
|
10
|
+
# end
|
11
|
+
|
12
|
+
respond_with(200) do
|
13
|
+
user = env["clerk"].user
|
14
|
+
user ? "Authenticated User: #{user.first_name} (#{user.id})" : "Not Authenticated"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def respond_with(status, plain_body = nil, &html_body)
|
21
|
+
return [status, {"Content-Type" => "text/plain; charset=utf-8"}, [plain_body]] unless block_given?
|
22
|
+
|
23
|
+
compiled = <<-HTML
|
24
|
+
<html>
|
25
|
+
<head>
|
26
|
+
<title>Rack</title>
|
27
|
+
<style>
|
28
|
+
html { font-family: monospace; }
|
29
|
+
@media (prefers-color-scheme: dark) {
|
30
|
+
html {
|
31
|
+
color: #FFE6E6FF;
|
32
|
+
background-color: #201D1E;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
</style>
|
36
|
+
<script
|
37
|
+
async
|
38
|
+
crossorigin="anonymous"
|
39
|
+
data-clerk-publishable-key="#{ENV["CLERK_PUBLISHABLE_KEY"]}"
|
40
|
+
src="#{ENV["CLERK_JS_URL"]}"
|
41
|
+
type="text/javascript"
|
42
|
+
></script>
|
43
|
+
<script>
|
44
|
+
window.addEventListener('load', async function () {
|
45
|
+
await Clerk.load()
|
46
|
+
const container = document.getElementById('auth-container')
|
47
|
+
if (Clerk.user) {
|
48
|
+
container.innerHTML = `<div id="user-button"></div>`
|
49
|
+
Clerk.mountUserButton(document.getElementById('user-button'))
|
50
|
+
} else {
|
51
|
+
container.innerHTML = `<div id="sign-in"></div>`
|
52
|
+
Clerk.mountSignIn(document.getElementById('sign-in'))
|
53
|
+
}
|
54
|
+
})
|
55
|
+
</script>
|
56
|
+
</head>
|
57
|
+
<body>
|
58
|
+
<h1>Rack</h1>
|
59
|
+
<h2>#{yield}</h2>
|
60
|
+
<div id="auth-container"></div>
|
61
|
+
</body>
|
62
|
+
</html>
|
63
|
+
HTML
|
64
|
+
|
65
|
+
[status, {"Content-Type" => "text/html; charset=utf-8"}, [compiled]]
|
66
|
+
end
|
67
|
+
end
|
data/apps/rack/config.ru
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "rack"
|
3
|
+
require "clerk/rack"
|
4
|
+
require "dotenv"
|
5
|
+
|
6
|
+
require_relative "app"
|
7
|
+
require_relative "middleware/disable_paths"
|
8
|
+
|
9
|
+
Dotenv.load(".env")
|
10
|
+
|
11
|
+
use DisablePaths, paths: ["/favicon.ico"]
|
12
|
+
use Clerk::Rack::Middleware
|
13
|
+
use Clerk::Rack::Reverification,
|
14
|
+
preset: Clerk::StepUp::Preset::LAX,
|
15
|
+
routes: ["/*"]
|
16
|
+
|
17
|
+
run App.new
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.
|
2
|
+
|
3
|
+
# Ignore git directory.
|
4
|
+
/.git/
|
5
|
+
/.gitignore
|
6
|
+
|
7
|
+
# Ignore bundler config.
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore all environment files.
|
11
|
+
/.env*
|
12
|
+
|
13
|
+
# Ignore all default key files.
|
14
|
+
/config/master.key
|
15
|
+
/config/credentials/*.key
|
16
|
+
|
17
|
+
# Ignore all logfiles and tempfiles.
|
18
|
+
/log/*
|
19
|
+
/tmp/*
|
20
|
+
!/log/.keep
|
21
|
+
!/tmp/.keep
|
22
|
+
|
23
|
+
# Ignore pidfiles, but keep the directory.
|
24
|
+
/tmp/pids/*
|
25
|
+
!/tmp/pids/.keep
|
26
|
+
|
27
|
+
# Ignore storage (uploaded files in development and any SQLite databases).
|
28
|
+
/storage/*
|
29
|
+
!/storage/.keep
|
30
|
+
/tmp/storage/*
|
31
|
+
!/tmp/storage/.keep
|
32
|
+
|
33
|
+
# Ignore CI service files.
|
34
|
+
/.github
|
35
|
+
|
36
|
+
# Ignore development files
|
37
|
+
/.devcontainer
|
38
|
+
|
39
|
+
# Ignore Docker-related files
|
40
|
+
/.dockerignore
|
41
|
+
/Dockerfile*
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# See https://git-scm.com/docs/gitattributes for more about git attribute files.
|
2
|
+
|
3
|
+
# Mark the database schema as having been generated.
|
4
|
+
db/schema.rb linguist-generated
|
5
|
+
|
6
|
+
# Mark any vendored files as having been vendored.
|
7
|
+
vendor/* linguist-vendored
|
8
|
+
config/credentials/*.yml.enc diff=rails_credentials
|
9
|
+
config/credentials.yml.enc diff=rails_credentials
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
|
2
|
+
#
|
3
|
+
# Temporary files generated by your text editor or operating system
|
4
|
+
# belong in git's global ignore instead:
|
5
|
+
# `$XDG_CONFIG_HOME/git/ignore` or `~/.config/git/ignore`
|
6
|
+
|
7
|
+
# Ignore bundler config.
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore all environment files.
|
11
|
+
/.env*
|
12
|
+
|
13
|
+
# Ignore all logfiles and tempfiles.
|
14
|
+
/log/*
|
15
|
+
/tmp/*
|
16
|
+
!/log/.keep
|
17
|
+
!/tmp/.keep
|
18
|
+
|
19
|
+
# Ignore pidfiles, but keep the directory.
|
20
|
+
/tmp/pids/*
|
21
|
+
!/tmp/pids/
|
22
|
+
!/tmp/pids/.keep
|
23
|
+
|
24
|
+
# Ignore storage (uploaded files in development and any SQLite databases).
|
25
|
+
/storage/*
|
26
|
+
!/storage/.keep
|
27
|
+
/tmp/storage/*
|
28
|
+
!/tmp/storage/
|
29
|
+
!/tmp/storage/.keep
|
30
|
+
|
31
|
+
# Ignore master key for decrypting credentials and more.
|
32
|
+
/config/master.key
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# A sample post-deploy hook
|
4
|
+
#
|
5
|
+
# These environment variables are available:
|
6
|
+
# KAMAL_RECORDED_AT
|
7
|
+
# KAMAL_PERFORMER
|
8
|
+
# KAMAL_VERSION
|
9
|
+
# KAMAL_HOSTS
|
10
|
+
# KAMAL_ROLE (if set)
|
11
|
+
# KAMAL_DESTINATION (if set)
|
12
|
+
# KAMAL_RUNTIME
|
13
|
+
|
14
|
+
echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# A sample pre-build hook
|
4
|
+
#
|
5
|
+
# Checks:
|
6
|
+
# 1. We have a clean checkout
|
7
|
+
# 2. A remote is configured
|
8
|
+
# 3. The branch has been pushed to the remote
|
9
|
+
# 4. The version we are deploying matches the remote
|
10
|
+
#
|
11
|
+
# These environment variables are available:
|
12
|
+
# KAMAL_RECORDED_AT
|
13
|
+
# KAMAL_PERFORMER
|
14
|
+
# KAMAL_VERSION
|
15
|
+
# KAMAL_HOSTS
|
16
|
+
# KAMAL_ROLE (if set)
|
17
|
+
# KAMAL_DESTINATION (if set)
|
18
|
+
|
19
|
+
if [ -n "$(git status --porcelain)" ]; then
|
20
|
+
echo "Git checkout is not clean, aborting..." >&2
|
21
|
+
git status --porcelain >&2
|
22
|
+
exit 1
|
23
|
+
fi
|
24
|
+
|
25
|
+
first_remote=$(git remote)
|
26
|
+
|
27
|
+
if [ -z "$first_remote" ]; then
|
28
|
+
echo "No git remote set, aborting..." >&2
|
29
|
+
exit 1
|
30
|
+
fi
|
31
|
+
|
32
|
+
current_branch=$(git branch --show-current)
|
33
|
+
|
34
|
+
if [ -z "$current_branch" ]; then
|
35
|
+
echo "Not on a git branch, aborting..." >&2
|
36
|
+
exit 1
|
37
|
+
fi
|
38
|
+
|
39
|
+
remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)
|
40
|
+
|
41
|
+
if [ -z "$remote_head" ]; then
|
42
|
+
echo "Branch not pushed to remote, aborting..." >&2
|
43
|
+
exit 1
|
44
|
+
fi
|
45
|
+
|
46
|
+
if [ "$KAMAL_VERSION" != "$remote_head" ]; then
|
47
|
+
echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
|
48
|
+
exit 1
|
49
|
+
fi
|
50
|
+
|
51
|
+
exit 0
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# A sample pre-connect check
|
4
|
+
#
|
5
|
+
# Warms DNS before connecting to hosts in parallel
|
6
|
+
#
|
7
|
+
# These environment variables are available:
|
8
|
+
# KAMAL_RECORDED_AT
|
9
|
+
# KAMAL_PERFORMER
|
10
|
+
# KAMAL_VERSION
|
11
|
+
# KAMAL_HOSTS
|
12
|
+
# KAMAL_ROLE (if set)
|
13
|
+
# KAMAL_DESTINATION (if set)
|
14
|
+
# KAMAL_RUNTIME
|
15
|
+
|
16
|
+
hosts = ENV["KAMAL_HOSTS"].split(",")
|
17
|
+
results = nil
|
18
|
+
max = 3
|
19
|
+
|
20
|
+
elapsed = Benchmark.realtime do
|
21
|
+
results = hosts.map do |host|
|
22
|
+
Thread.new do
|
23
|
+
tries = 1
|
24
|
+
|
25
|
+
begin
|
26
|
+
Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
|
27
|
+
rescue SocketError
|
28
|
+
if tries < max
|
29
|
+
puts "Retrying DNS warmup: #{host}"
|
30
|
+
tries += 1
|
31
|
+
sleep rand
|
32
|
+
retry
|
33
|
+
else
|
34
|
+
puts "DNS warmup failed: #{host}"
|
35
|
+
host
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
tries
|
40
|
+
end
|
41
|
+
end.map(&:value)
|
42
|
+
end
|
43
|
+
|
44
|
+
retries = results.sum - hosts.size
|
45
|
+
nopes = results.count { |r| r == max }
|
46
|
+
|
47
|
+
puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]
|