rodauth-rails 0.4.0 → 0.6.1
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 +4 -4
- data/CHANGELOG.md +42 -0
- data/README.md +177 -77
- data/lib/generators/rodauth/install_generator.rb +28 -18
- data/lib/generators/rodauth/migration/account_expiration.erb +7 -0
- data/lib/generators/rodauth/migration/active_sessions.erb +7 -0
- data/lib/generators/rodauth/migration/audit_logging.erb +16 -0
- data/lib/generators/rodauth/migration/base.erb +19 -0
- data/lib/generators/rodauth/migration/disallow_password_reuse.erb +5 -0
- data/lib/generators/rodauth/migration/email_auth.erb +7 -0
- data/lib/generators/rodauth/migration/jwt_refresh.erb +7 -0
- data/lib/generators/rodauth/migration/lockout.erb +11 -0
- data/lib/generators/rodauth/migration/otp.erb +7 -0
- data/lib/generators/rodauth/migration/password_expiration.erb +5 -0
- data/lib/generators/rodauth/migration/recovery_codes.erb +6 -0
- data/lib/generators/rodauth/migration/remember.erb +6 -0
- data/lib/generators/rodauth/migration/reset_password.erb +7 -0
- data/lib/generators/rodauth/migration/single_session.erb +5 -0
- data/lib/generators/rodauth/migration/sms_codes.erb +8 -0
- data/lib/generators/rodauth/migration/verify_account.erb +7 -0
- data/lib/generators/rodauth/migration/verify_login_change.erb +7 -0
- data/lib/generators/rodauth/migration/webauthn.erb +12 -0
- data/lib/generators/rodauth/migration_generator.rb +32 -0
- data/lib/generators/rodauth/migration_helpers.rb +69 -0
- data/lib/generators/rodauth/templates/app/controllers/rodauth_controller.rb +2 -1
- data/lib/generators/rodauth/templates/app/lib/rodauth_app.rb +18 -18
- data/lib/generators/rodauth/templates/config/initializers/sequel.rb +1 -5
- data/lib/generators/rodauth/templates/db/migrate/create_rodauth.rb +2 -176
- data/lib/rodauth/rails.rb +23 -4
- data/lib/rodauth/rails/app.rb +3 -1
- data/lib/rodauth/rails/app/flash.rb +1 -1
- data/lib/rodauth/rails/app/middleware.rb +26 -0
- data/lib/rodauth/rails/feature.rb +92 -25
- data/lib/rodauth/rails/railtie.rb +11 -0
- data/lib/rodauth/rails/tasks.rake +28 -0
- data/lib/rodauth/rails/version.rb +1 -1
- data/rodauth-rails.gemspec +3 -3
- metadata +29 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9805b35cefee7e30cc6f7190e2ace9e7ea75c20f40651eb364edafea2f2382f7
|
4
|
+
data.tar.gz: 503b821866aaf2b6aa108265ed8015869a8c8a6a73e910aa3c38b35c5a542ac1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a3e69b6d62f20ee5bc5a13c89acd2974401830a4f0f8917cc7716c9a5ccaad021a20c0f3269a211336b648bd8eb65ae60094c90a039fa1d3968eaf322ec2e47
|
7
|
+
data.tar.gz: 567cf154e656f7062029e207d92149fa8cf2c87404d1ba72fef6327cb31f928d0bcf453a4a0d55f71740251cb74f8b6829b8c775373daec4fe638690cd702104
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,45 @@
|
|
1
|
+
## 0.6.1 (2020-11-25)
|
2
|
+
|
3
|
+
* Generate the Rodauth controller for API-only Rails apps as well (@janko)
|
4
|
+
|
5
|
+
* Fix remember cookie deadline not extending in remember feature (@janko)
|
6
|
+
|
7
|
+
## 0.6.0 (2020-11-22)
|
8
|
+
|
9
|
+
* Add `Rodauth::Rails.rodauth` method for retrieving Rodauth instance outside of request context (@janko)
|
10
|
+
|
11
|
+
* Add default Action Dispatch response headers in Rodauth responses (@janko)
|
12
|
+
|
13
|
+
* Run controller rescue handlers around Rodauth actions (@janko)
|
14
|
+
|
15
|
+
* Run controller action callbacks around Rodauth actions (@janko)
|
16
|
+
|
17
|
+
## 0.5.0 (2020-11-16)
|
18
|
+
|
19
|
+
* Support more Active Record adapters in `rodauth:install` generator (@janko)
|
20
|
+
|
21
|
+
* Add `rodauth:migration` generator for creating tables of specified features (@janko)
|
22
|
+
|
23
|
+
* Use UUIDs for primary keys if so configured in Rails generators (@janko)
|
24
|
+
|
25
|
+
* Add `rodauth:routes` rake task for printing routes handled by Rodauth middleware (@janko)
|
26
|
+
|
27
|
+
## 0.4.2 (2020-11-08)
|
28
|
+
|
29
|
+
* Drop support for Ruby 2.2 (@janko)
|
30
|
+
|
31
|
+
* Bump `sequel-activerecord_connection` dependency to 1.1+ (@janko)
|
32
|
+
|
33
|
+
* Set default bcrypt hash cost to `1` in tests (@janko)
|
34
|
+
|
35
|
+
* Call `AR::Base.connection_db_config` on Rails 6.1+ in `rodauth:install` generator (@janko)
|
36
|
+
|
37
|
+
## 0.4.1 (2020-11-02)
|
38
|
+
|
39
|
+
* Don't generate `RodauthController` in API-only mode (@janko)
|
40
|
+
|
41
|
+
* Pass `test: false` to Sequel in the `sequel.rb` initializer (@janko)
|
42
|
+
|
1
43
|
## 0.4.0 (2020-11-02)
|
2
44
|
|
3
45
|
* Support Rails API-only mode (@janko)
|
data/README.md
CHANGED
@@ -4,16 +4,22 @@ Provides Rails integration for the [Rodauth] authentication framework.
|
|
4
4
|
|
5
5
|
## Resources
|
6
6
|
|
7
|
+
Useful links:
|
8
|
+
|
7
9
|
* [Rodauth documentation](http://rodauth.jeremyevans.net/documentation.html)
|
8
|
-
* [rodauth-rails wiki](https://github.com/janko/rodauth-rails/wiki)
|
9
10
|
* [Rails demo](https://github.com/janko/rodauth-demo-rails)
|
10
11
|
|
12
|
+
Articles:
|
13
|
+
|
14
|
+
* [Rodauth: A Refreshing Authentication Solution for Ruby](https://janko.io/rodauth-a-refreshing-authentication-solution-for-ruby/)
|
15
|
+
* [Adding Authentication in Rails 6 with Rodauth](https://janko.io/adding-authentication-in-rails-with-rodauth/)
|
16
|
+
|
11
17
|
## Installation
|
12
18
|
|
13
19
|
Add the gem to your Gemfile:
|
14
20
|
|
15
21
|
```rb
|
16
|
-
gem "rodauth-rails", "~> 0.
|
22
|
+
gem "rodauth-rails", "~> 0.6"
|
17
23
|
|
18
24
|
# gem "jwt", require: false # for JWT feature
|
19
25
|
# gem "rotp", require: false # for OTP feature
|
@@ -54,7 +60,6 @@ class CreateRodauth < ActiveRecord::Migration
|
|
54
60
|
create_table :account_verification_keys do |t| ... end
|
55
61
|
create_table :account_login_change_keys do |t| ... end
|
56
62
|
create_table :account_remember_keys do |t| ... end
|
57
|
-
# ...
|
58
63
|
end
|
59
64
|
end
|
60
65
|
```
|
@@ -88,7 +93,7 @@ ActiveRecord connection.
|
|
88
93
|
require "sequel/core"
|
89
94
|
|
90
95
|
# initialize Sequel and have it reuse Active Record's database connection
|
91
|
-
DB = Sequel.
|
96
|
+
DB = Sequel.connect("postgresql://", extensions: :activerecord_connection)
|
92
97
|
```
|
93
98
|
|
94
99
|
### Rodauth app
|
@@ -112,8 +117,9 @@ end
|
|
112
117
|
|
113
118
|
### Controller
|
114
119
|
|
115
|
-
Your Rodauth app will by default use `RodauthController` for view rendering
|
116
|
-
and
|
120
|
+
Your Rodauth app will by default use `RodauthController` for view rendering,
|
121
|
+
CSRF protection, and running controller callbacks and rescue handlers around
|
122
|
+
Rodauth actions.
|
117
123
|
|
118
124
|
```rb
|
119
125
|
# app/controllers/rodauth_controller.rb
|
@@ -121,7 +127,7 @@ class RodauthController < ApplicationController
|
|
121
127
|
end
|
122
128
|
```
|
123
129
|
|
124
|
-
### Account
|
130
|
+
### Account model
|
125
131
|
|
126
132
|
Rodauth stores user accounts in the `accounts` table, so the generator will
|
127
133
|
also create an `Account` model for custom use.
|
@@ -132,10 +138,34 @@ class Account < ApplicationRecord
|
|
132
138
|
end
|
133
139
|
```
|
134
140
|
|
135
|
-
##
|
141
|
+
## Usage
|
142
|
+
|
143
|
+
### Routes
|
144
|
+
|
145
|
+
We can see the list of routes our Rodauth middleware handles:
|
136
146
|
|
137
|
-
|
138
|
-
|
147
|
+
```sh
|
148
|
+
$ rails rodauth:routes
|
149
|
+
```
|
150
|
+
```
|
151
|
+
Routes handled by RodauthApp:
|
152
|
+
|
153
|
+
/login rodauth.login_path
|
154
|
+
/create-account rodauth.create_account_path
|
155
|
+
/verify-account-resend rodauth.verify_account_resend_path
|
156
|
+
/verify-account rodauth.verify_account_path
|
157
|
+
/change-password rodauth.change_password_path
|
158
|
+
/change-login rodauth.change_login_path
|
159
|
+
/logout rodauth.logout_path
|
160
|
+
/remember rodauth.remember_path
|
161
|
+
/reset-password-request rodauth.reset_password_request_path
|
162
|
+
/reset-password rodauth.reset_password_path
|
163
|
+
/verify-login-change rodauth.verify_login_change_path
|
164
|
+
/close-account rodauth.close_account_path
|
165
|
+
```
|
166
|
+
|
167
|
+
Using this information, we could add some basic authentication links to our
|
168
|
+
navigation header:
|
139
169
|
|
140
170
|
```erb
|
141
171
|
<ul>
|
@@ -148,43 +178,48 @@ page:
|
|
148
178
|
</ul>
|
149
179
|
```
|
150
180
|
|
151
|
-
These
|
181
|
+
These routes are fully functional, feel free to visit them and interact with the
|
152
182
|
pages. The templates that ship with Rodauth aim to provide a complete
|
153
183
|
authentication experience, and the forms use [Bootstrap] markup.
|
154
184
|
|
155
|
-
|
156
|
-
|
185
|
+
### Current account
|
186
|
+
|
187
|
+
To be able to fetch currently authenticated account, let's define a
|
188
|
+
`#current_account` method that fetches the account id from session and
|
189
|
+
retrieves the corresponding account record:
|
157
190
|
|
158
191
|
```rb
|
159
192
|
# app/controllers/application_controller.rb
|
160
193
|
class ApplicationController < ActionController::Base
|
161
|
-
before_action :
|
194
|
+
before_action :current_account, if: -> { rodauth.authenticated? }
|
162
195
|
|
163
196
|
private
|
164
197
|
|
165
|
-
def
|
166
|
-
@current_account
|
198
|
+
def current_account
|
199
|
+
@current_account ||= Account.find(rodauth.session_value)
|
167
200
|
rescue ActiveRecord::RecordNotFound
|
168
201
|
rodauth.logout
|
169
202
|
rodauth.login_required
|
170
203
|
end
|
171
|
-
|
172
|
-
attr_reader :current_account
|
173
204
|
helper_method :current_account
|
174
205
|
end
|
175
206
|
```
|
207
|
+
|
208
|
+
This allows us to access the current account in controllers and views:
|
209
|
+
|
176
210
|
```erb
|
177
211
|
<p>Authenticated as: <%= current_account.email %></p>
|
178
212
|
```
|
179
213
|
|
180
214
|
### Requiring authentication
|
181
215
|
|
182
|
-
|
183
|
-
|
184
|
-
the authentication logic
|
216
|
+
We'll likely want to require authentication for certain parts of our app,
|
217
|
+
redirecting the user to the login page if they're not logged in. We can do this
|
218
|
+
in our Rodauth app's routing block, which helps keep the authentication logic
|
219
|
+
encapsulated:
|
185
220
|
|
186
221
|
```rb
|
187
|
-
# lib/rodauth_app.rb
|
222
|
+
# app/lib/rodauth_app.rb
|
188
223
|
class RodauthApp < Rodauth::Rails::App
|
189
224
|
# ...
|
190
225
|
route do |r|
|
@@ -239,9 +274,9 @@ end
|
|
239
274
|
|
240
275
|
### Views
|
241
276
|
|
242
|
-
The templates built into Rodauth are useful when getting started, but
|
243
|
-
|
244
|
-
|
277
|
+
The templates built into Rodauth are useful when getting started, but soon
|
278
|
+
you'll want to start editing the markup. You can run the following command to
|
279
|
+
copy Rodauth templates into your Rails app:
|
245
280
|
|
246
281
|
```sh
|
247
282
|
$ rails generate rodauth:views
|
@@ -265,7 +300,7 @@ $ rails generate rodauth:views --all
|
|
265
300
|
```
|
266
301
|
|
267
302
|
You can also tell the generator to create views into another directory (in this
|
268
|
-
case
|
303
|
+
case make sure to rename the Rodauth controller accordingly):
|
269
304
|
|
270
305
|
```sh
|
271
306
|
# generates views into app/views/authentication
|
@@ -300,11 +335,11 @@ end
|
|
300
335
|
|
301
336
|
### Mailer
|
302
337
|
|
303
|
-
Rodauth may send emails as part of
|
304
|
-
can be customized:
|
338
|
+
Depending on the features you've enabled, Rodauth may send emails as part of
|
339
|
+
the authentication flow. Most email settings can be customized:
|
305
340
|
|
306
341
|
```rb
|
307
|
-
# lib/rodauth_app.rb
|
342
|
+
# app/lib/rodauth_app.rb
|
308
343
|
class RodauthApp < Rodauth::Rails::App
|
309
344
|
# ...
|
310
345
|
configure do
|
@@ -345,46 +380,117 @@ end
|
|
345
380
|
```
|
346
381
|
|
347
382
|
You can then uncomment the lines in your Rodauth configuration to have it call
|
348
|
-
your mailer. If you've enabled additional authentication features
|
349
|
-
override their `
|
383
|
+
your mailer. If you've enabled additional authentication features that send
|
384
|
+
emails, make sure to override their `create_*_email` methods as well.
|
350
385
|
|
351
386
|
```rb
|
352
|
-
# lib/rodauth_app.rb
|
387
|
+
# app/lib/rodauth_app.rb
|
353
388
|
class RodauthApp < Rodauth::Rails::App
|
354
389
|
# ...
|
355
390
|
configure do
|
356
391
|
# ...
|
357
|
-
|
358
|
-
|
392
|
+
create_reset_password_email do
|
393
|
+
RodauthMailer.reset_password(email_to, reset_password_email_link)
|
359
394
|
end
|
360
|
-
|
361
|
-
|
395
|
+
create_verify_account_email do
|
396
|
+
RodauthMailer.verify_account(email_to, verify_account_email_link)
|
362
397
|
end
|
363
|
-
|
364
|
-
|
398
|
+
create_verify_login_change_email do |login|
|
399
|
+
RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
|
365
400
|
end
|
366
|
-
|
367
|
-
|
401
|
+
create_password_changed_email do
|
402
|
+
RodauthMailer.password_changed(email_to)
|
368
403
|
end
|
369
|
-
#
|
370
|
-
#
|
404
|
+
# create_email_auth_email do
|
405
|
+
# RodauthMailer.email_auth(email_to, email_auth_email_link)
|
371
406
|
# end
|
372
|
-
#
|
373
|
-
#
|
407
|
+
# create_unlock_account_email do
|
408
|
+
# RodauthMailer.unlock_account(email_to, unlock_account_email_link)
|
374
409
|
# end
|
375
|
-
|
410
|
+
send_email do |email|
|
376
411
|
# queue email delivery on the mailer after the transaction commits
|
377
|
-
|
378
|
-
db.after_commit do
|
379
|
-
RodauthMailer.public_send(type, *args).deliver_later
|
380
|
-
end
|
381
|
-
end
|
412
|
+
db.after_commit { email.deliver_later }
|
382
413
|
end
|
383
414
|
# ...
|
384
415
|
end
|
385
416
|
end
|
386
417
|
```
|
387
418
|
|
419
|
+
This approach can be used even if you're using a 3rd-party service for
|
420
|
+
transactional emails, where emails are sent via API requests instead of
|
421
|
+
SMTP. Whatever the `create_*_email` block returns will be passed to
|
422
|
+
`send_email`, so you can be creative.
|
423
|
+
|
424
|
+
### Migrations
|
425
|
+
|
426
|
+
The install generator will create a migration for tables used by the Rodauth
|
427
|
+
features enabled by default. For any additional features, you can use the
|
428
|
+
migration generator to create the corresponding tables:
|
429
|
+
|
430
|
+
```sh
|
431
|
+
$ rails generate rodauth:migration otp sms_codes recovery_codes
|
432
|
+
```
|
433
|
+
```rb
|
434
|
+
# db/migration/*_create_rodauth_otp_sms_codes_recovery_codes.rb
|
435
|
+
class CreateRodauthOtpSmsCodesRecoveryCodes < ActiveRecord::Migration
|
436
|
+
def change
|
437
|
+
create_table :account_otp_keys do |t| ... end
|
438
|
+
create_table :account_sms_codes do |t| ... end
|
439
|
+
create_table :account_recovery_codes do |t| ... end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
```
|
443
|
+
|
444
|
+
### JSON API
|
445
|
+
|
446
|
+
JSON API support in Rodauth is provided by the [JWT feature]. First you'll need
|
447
|
+
to add the [JWT gem] to your Gemfile:
|
448
|
+
|
449
|
+
```rb
|
450
|
+
gem "jwt"
|
451
|
+
```
|
452
|
+
|
453
|
+
The following configuration will enable the Rodauth endpoints to be accessed
|
454
|
+
via JSON requests (in addition to HTML requests):
|
455
|
+
|
456
|
+
```rb
|
457
|
+
# app/lib/rodauth_app.rb
|
458
|
+
class RodauthApp < Rodauth::Rails::App
|
459
|
+
configure(json: true) do
|
460
|
+
# ...
|
461
|
+
enable :jwt
|
462
|
+
jwt_secret "...your secret key..."
|
463
|
+
# ...
|
464
|
+
end
|
465
|
+
end
|
466
|
+
```
|
467
|
+
|
468
|
+
If you want the endpoints to be only accessible via JSON requests, or if your
|
469
|
+
Rails app is in API-only mode, instead of `json: true` pass `json: :only` to
|
470
|
+
the configure method.
|
471
|
+
|
472
|
+
Make sure to store the `jwt_secret` in a secure place, such as Rails
|
473
|
+
credentials or environment variables.
|
474
|
+
|
475
|
+
### Rodauth instance
|
476
|
+
|
477
|
+
In some cases you might need to use Rodauth more programmatically, and perform
|
478
|
+
Rodauth operations outside of the request context. rodauth-rails gives you the
|
479
|
+
ability to retrieve the Rodauth instance:
|
480
|
+
|
481
|
+
```rb
|
482
|
+
rodauth = Rodauth::Rails.rodauth # or Rodauth::Rails.rodauth(:secondary)
|
483
|
+
|
484
|
+
rodauth.login_url #=> "https://example.com/login"
|
485
|
+
rodauth.account_from_login("user@example.com") # loads user by email
|
486
|
+
rodauth.password_match?("secret") #=> true
|
487
|
+
rodauth.setup_account_verification
|
488
|
+
rodauth.close_account
|
489
|
+
```
|
490
|
+
|
491
|
+
This Rodauth instance will be initialized with basic Rack env that allows is it
|
492
|
+
to generate URLs, using `config.action_mailer.default_url_options` options.
|
493
|
+
|
388
494
|
## How it works
|
389
495
|
|
390
496
|
### Middleware
|
@@ -429,11 +535,12 @@ end
|
|
429
535
|
The `Rodauth::Rails::App` class is a [Roda] subclass that provides Rails
|
430
536
|
integration for Rodauth:
|
431
537
|
|
432
|
-
* uses
|
433
|
-
* uses
|
538
|
+
* uses Action Dispatch flash instead of Roda's
|
539
|
+
* uses Action Dispatch CSRF protection instead of Roda's
|
434
540
|
* sets [HMAC] secret to Rails' secret key base
|
435
|
-
* uses
|
436
|
-
*
|
541
|
+
* uses Action Controller for rendering templates
|
542
|
+
* runs Action Controller callbacks & rescue handlers around Rodauth actions
|
543
|
+
* uses Action Mailer for sending emails
|
437
544
|
|
438
545
|
The `configure { ... }` method wraps configuring the Rodauth plugin, forwarding
|
439
546
|
any additional [plugin options].
|
@@ -490,28 +597,6 @@ Rodauth::Rails.configure do |config|
|
|
490
597
|
end
|
491
598
|
```
|
492
599
|
|
493
|
-
## Working with JWT
|
494
|
-
|
495
|
-
To use Rodauth's [JWT feature], you'll need to load Roda's JSON support in
|
496
|
-
`configure`:
|
497
|
-
|
498
|
-
```rb
|
499
|
-
# lib/rodauth_app.rb
|
500
|
-
class RodauthApp < Rodauth::Rails::App
|
501
|
-
configure(json: true) do
|
502
|
-
enable :jwt
|
503
|
-
jwt_secret "...your secret key..."
|
504
|
-
# your configuration
|
505
|
-
end
|
506
|
-
end
|
507
|
-
```
|
508
|
-
|
509
|
-
Make sure to store the `jwt_secret` in a secure place, such as Rails
|
510
|
-
credentials or environment variables.
|
511
|
-
|
512
|
-
Rodauth's JWT feature depends on the [JWT gem], so make sure to add it to your
|
513
|
-
Gemfile.
|
514
|
-
|
515
600
|
## Testing
|
516
601
|
|
517
602
|
If you're writing system tests, it's generally better to go through the actual
|
@@ -579,6 +664,22 @@ disables the use of database functions, though you can always turn it back on.
|
|
579
664
|
use_database_authentication_functions? true
|
580
665
|
```
|
581
666
|
|
667
|
+
To create the database functions, pass the Sequel database object into the
|
668
|
+
Rodauth method for creating database functions:
|
669
|
+
|
670
|
+
```rb
|
671
|
+
# db/migrate/*_create_rodauth_database_functions.rb
|
672
|
+
class CreateRodauthDatabaseFunctions < ActiveRecord::Migration
|
673
|
+
def up
|
674
|
+
Rodauth.create_database_authentication_functions(DB)
|
675
|
+
end
|
676
|
+
|
677
|
+
def down
|
678
|
+
Rodauth.drop_database_authentication_functions(DB)
|
679
|
+
end
|
680
|
+
end
|
681
|
+
```
|
682
|
+
|
582
683
|
### Account statuses
|
583
684
|
|
584
685
|
The recommended [Rodauth migration] stores possible account status values in a
|
@@ -631,7 +732,6 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
|
|
631
732
|
|
632
733
|
[Rodauth]: https://github.com/jeremyevans/rodauth
|
633
734
|
[Sequel]: https://github.com/jeremyevans/sequel
|
634
|
-
[rendering views outside of controllers]: https://blog.bigbinary.com/2016/01/08/rendering-views-outside-of-controllers-in-rails-5.html
|
635
735
|
[feature documentation]: http://rodauth.jeremyevans.net/documentation.html
|
636
736
|
[JWT feature]: http://rodauth.jeremyevans.net/rdoc/files/doc/jwt_rdoc.html
|
637
737
|
[JWT gem]: https://github.com/jwt/ruby-jwt
|