rodauth-rails 0.4.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -0
- data/README.md +187 -52
- data/lib/generators/rodauth/install_generator.rb +28 -20
- 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 -20
- 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 +33 -4
- data/lib/rodauth/rails/app.rb +4 -2
- data/lib/rodauth/rails/app/flash.rb +1 -1
- data/lib/rodauth/rails/app/middleware.rb +26 -0
- data/lib/rodauth/rails/feature.rb +98 -30
- 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: 8163d64892cbebd867182d15148f3099abb3ed49ae3e07a89a5adea6606623d2
|
4
|
+
data.tar.gz: 3cc7990e0af8e5ffb2ac959f989fb45cf538490412adfc908571823e5dd7b160
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99005d6864310fa3a36f8314a13588900a5ac1559af7a77d75cb5aba66b0b829d32c83fe66a3f5a7ced098de32b39396edd666919177836bb84b35a0de3a558b
|
7
|
+
data.tar.gz: 2d66b5ab43d05b26483cb3d69181c506b19a937fa77a2d7d66a38708f6357fae7bd2e605cc0a96affdd8fed822076dccb1603577338e68620c70a816fc45db7a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,45 @@
|
|
1
|
+
## 0.7.0 (2020-11-27)
|
2
|
+
|
3
|
+
* Add `#rails_controller_eval` method for running code in context of a controller instance (@janko)
|
4
|
+
|
5
|
+
* Detect `secret_key_base` from credentials and `$SECRET_KEY_BASE` environment variable (@janko)
|
6
|
+
|
7
|
+
## 0.6.1 (2020-11-25)
|
8
|
+
|
9
|
+
* Generate the Rodauth controller for API-only Rails apps as well (@janko)
|
10
|
+
|
11
|
+
* Fix remember cookie deadline not extending in remember feature (@janko)
|
12
|
+
|
13
|
+
## 0.6.0 (2020-11-22)
|
14
|
+
|
15
|
+
* Add `Rodauth::Rails.rodauth` method for retrieving Rodauth instance outside of request context (@janko)
|
16
|
+
|
17
|
+
* Add default Action Dispatch response headers in Rodauth responses (@janko)
|
18
|
+
|
19
|
+
* Run controller rescue handlers around Rodauth actions (@janko)
|
20
|
+
|
21
|
+
* Run controller action callbacks around Rodauth actions (@janko)
|
22
|
+
|
23
|
+
## 0.5.0 (2020-11-16)
|
24
|
+
|
25
|
+
* Support more Active Record adapters in `rodauth:install` generator (@janko)
|
26
|
+
|
27
|
+
* Add `rodauth:migration` generator for creating tables of specified features (@janko)
|
28
|
+
|
29
|
+
* Use UUIDs for primary keys if so configured in Rails generators (@janko)
|
30
|
+
|
31
|
+
* Add `rodauth:routes` rake task for printing routes handled by Rodauth middleware (@janko)
|
32
|
+
|
33
|
+
## 0.4.2 (2020-11-08)
|
34
|
+
|
35
|
+
* Drop support for Ruby 2.2 (@janko)
|
36
|
+
|
37
|
+
* Bump `sequel-activerecord_connection` dependency to 1.1+ (@janko)
|
38
|
+
|
39
|
+
* Set default bcrypt hash cost to `1` in tests (@janko)
|
40
|
+
|
41
|
+
* Call `AR::Base.connection_db_config` on Rails 6.1+ in `rodauth:install` generator (@janko)
|
42
|
+
|
1
43
|
## 0.4.1 (2020-11-02)
|
2
44
|
|
3
45
|
* Don't generate `RodauthController` in API-only mode (@janko)
|
data/README.md
CHANGED
@@ -4,16 +4,39 @@ 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
|
+
|
17
|
+
## Upgrading
|
18
|
+
|
19
|
+
### Upgrading to 0.7.0
|
20
|
+
|
21
|
+
Starting from version 0.7.0, rodauth-rails now correctly detects Rails
|
22
|
+
application's `secret_key_base` when setting default `hmac_secret`, including
|
23
|
+
when it's set via credentials or `$SECRET_KEY_BASE` environment variable. This
|
24
|
+
means authentication will be more secure by default, and Rodauth features that
|
25
|
+
require `hmac_secret` should now work automatically as well.
|
26
|
+
|
27
|
+
However, if you've already been using rodauth-rails in production, where the
|
28
|
+
`secret_key_base` is set via credentials or environment variable and `hmac_secret`
|
29
|
+
was not explicitly set, the fact that your authentication will now start using
|
30
|
+
HMACs has backwards compatibility considerations. See the [Rodauth
|
31
|
+
documentation](hmac) for instructions on how to safely transition, or just set
|
32
|
+
`hmac_secret nil` in your Rodauth configuration.
|
33
|
+
|
11
34
|
## Installation
|
12
35
|
|
13
36
|
Add the gem to your Gemfile:
|
14
37
|
|
15
38
|
```rb
|
16
|
-
gem "rodauth-rails", "~> 0.
|
39
|
+
gem "rodauth-rails", "~> 0.6"
|
17
40
|
|
18
41
|
# gem "jwt", require: false # for JWT feature
|
19
42
|
# gem "rotp", require: false # for OTP feature
|
@@ -54,7 +77,6 @@ class CreateRodauth < ActiveRecord::Migration
|
|
54
77
|
create_table :account_verification_keys do |t| ... end
|
55
78
|
create_table :account_login_change_keys do |t| ... end
|
56
79
|
create_table :account_remember_keys do |t| ... end
|
57
|
-
# ...
|
58
80
|
end
|
59
81
|
end
|
60
82
|
```
|
@@ -88,7 +110,7 @@ ActiveRecord connection.
|
|
88
110
|
require "sequel/core"
|
89
111
|
|
90
112
|
# initialize Sequel and have it reuse Active Record's database connection
|
91
|
-
DB = Sequel.
|
113
|
+
DB = Sequel.connect("postgresql://", extensions: :activerecord_connection)
|
92
114
|
```
|
93
115
|
|
94
116
|
### Rodauth app
|
@@ -112,8 +134,9 @@ end
|
|
112
134
|
|
113
135
|
### Controller
|
114
136
|
|
115
|
-
Your Rodauth app will by default use `RodauthController` for view rendering
|
116
|
-
and
|
137
|
+
Your Rodauth app will by default use `RodauthController` for view rendering,
|
138
|
+
CSRF protection, and running controller callbacks and rescue handlers around
|
139
|
+
Rodauth actions.
|
117
140
|
|
118
141
|
```rb
|
119
142
|
# app/controllers/rodauth_controller.rb
|
@@ -121,7 +144,7 @@ class RodauthController < ApplicationController
|
|
121
144
|
end
|
122
145
|
```
|
123
146
|
|
124
|
-
### Account
|
147
|
+
### Account model
|
125
148
|
|
126
149
|
Rodauth stores user accounts in the `accounts` table, so the generator will
|
127
150
|
also create an `Account` model for custom use.
|
@@ -132,10 +155,34 @@ class Account < ApplicationRecord
|
|
132
155
|
end
|
133
156
|
```
|
134
157
|
|
135
|
-
##
|
158
|
+
## Usage
|
159
|
+
|
160
|
+
### Routes
|
161
|
+
|
162
|
+
We can see the list of routes our Rodauth middleware handles:
|
163
|
+
|
164
|
+
```sh
|
165
|
+
$ rails rodauth:routes
|
166
|
+
```
|
167
|
+
```
|
168
|
+
Routes handled by RodauthApp:
|
169
|
+
|
170
|
+
/login rodauth.login_path
|
171
|
+
/create-account rodauth.create_account_path
|
172
|
+
/verify-account-resend rodauth.verify_account_resend_path
|
173
|
+
/verify-account rodauth.verify_account_path
|
174
|
+
/change-password rodauth.change_password_path
|
175
|
+
/change-login rodauth.change_login_path
|
176
|
+
/logout rodauth.logout_path
|
177
|
+
/remember rodauth.remember_path
|
178
|
+
/reset-password-request rodauth.reset_password_request_path
|
179
|
+
/reset-password rodauth.reset_password_path
|
180
|
+
/verify-login-change rodauth.verify_login_change_path
|
181
|
+
/close-account rodauth.close_account_path
|
182
|
+
```
|
136
183
|
|
137
|
-
|
138
|
-
|
184
|
+
Using this information, we could add some basic authentication links to our
|
185
|
+
navigation header:
|
139
186
|
|
140
187
|
```erb
|
141
188
|
<ul>
|
@@ -148,40 +195,45 @@ page:
|
|
148
195
|
</ul>
|
149
196
|
```
|
150
197
|
|
151
|
-
These
|
198
|
+
These routes are fully functional, feel free to visit them and interact with the
|
152
199
|
pages. The templates that ship with Rodauth aim to provide a complete
|
153
200
|
authentication experience, and the forms use [Bootstrap] markup.
|
154
201
|
|
155
|
-
|
156
|
-
|
202
|
+
### Current account
|
203
|
+
|
204
|
+
To be able to fetch currently authenticated account, let's define a
|
205
|
+
`#current_account` method that fetches the account id from session and
|
206
|
+
retrieves the corresponding account record:
|
157
207
|
|
158
208
|
```rb
|
159
209
|
# app/controllers/application_controller.rb
|
160
210
|
class ApplicationController < ActionController::Base
|
161
|
-
before_action :
|
211
|
+
before_action :current_account, if: -> { rodauth.authenticated? }
|
162
212
|
|
163
213
|
private
|
164
214
|
|
165
|
-
def
|
166
|
-
@current_account
|
215
|
+
def current_account
|
216
|
+
@current_account ||= Account.find(rodauth.session_value)
|
167
217
|
rescue ActiveRecord::RecordNotFound
|
168
218
|
rodauth.logout
|
169
219
|
rodauth.login_required
|
170
220
|
end
|
171
|
-
|
172
|
-
attr_reader :current_account
|
173
221
|
helper_method :current_account
|
174
222
|
end
|
175
223
|
```
|
224
|
+
|
225
|
+
This allows us to access the current account in controllers and views:
|
226
|
+
|
176
227
|
```erb
|
177
228
|
<p>Authenticated as: <%= current_account.email %></p>
|
178
229
|
```
|
179
230
|
|
180
231
|
### Requiring authentication
|
181
232
|
|
182
|
-
|
183
|
-
|
184
|
-
the authentication logic
|
233
|
+
We'll likely want to require authentication for certain parts of our app,
|
234
|
+
redirecting the user to the login page if they're not logged in. We can do this
|
235
|
+
in our Rodauth app's routing block, which helps keep the authentication logic
|
236
|
+
encapsulated:
|
185
237
|
|
186
238
|
```rb
|
187
239
|
# app/lib/rodauth_app.rb
|
@@ -239,9 +291,9 @@ end
|
|
239
291
|
|
240
292
|
### Views
|
241
293
|
|
242
|
-
The templates built into Rodauth are useful when getting started, but
|
243
|
-
|
244
|
-
|
294
|
+
The templates built into Rodauth are useful when getting started, but soon
|
295
|
+
you'll want to start editing the markup. You can run the following command to
|
296
|
+
copy Rodauth templates into your Rails app:
|
245
297
|
|
246
298
|
```sh
|
247
299
|
$ rails generate rodauth:views
|
@@ -265,7 +317,7 @@ $ rails generate rodauth:views --all
|
|
265
317
|
```
|
266
318
|
|
267
319
|
You can also tell the generator to create views into another directory (in this
|
268
|
-
case
|
320
|
+
case make sure to rename the Rodauth controller accordingly):
|
269
321
|
|
270
322
|
```sh
|
271
323
|
# generates views into app/views/authentication
|
@@ -300,8 +352,8 @@ end
|
|
300
352
|
|
301
353
|
### Mailer
|
302
354
|
|
303
|
-
Rodauth may send emails as part of
|
304
|
-
can be customized:
|
355
|
+
Depending on the features you've enabled, Rodauth may send emails as part of
|
356
|
+
the authentication flow. Most email settings can be customized:
|
305
357
|
|
306
358
|
```rb
|
307
359
|
# app/lib/rodauth_app.rb
|
@@ -345,8 +397,8 @@ end
|
|
345
397
|
```
|
346
398
|
|
347
399
|
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 `
|
400
|
+
your mailer. If you've enabled additional authentication features that send
|
401
|
+
emails, make sure to override their `create_*_email` methods as well.
|
350
402
|
|
351
403
|
```rb
|
352
404
|
# app/lib/rodauth_app.rb
|
@@ -354,37 +406,58 @@ class RodauthApp < Rodauth::Rails::App
|
|
354
406
|
# ...
|
355
407
|
configure do
|
356
408
|
# ...
|
357
|
-
|
358
|
-
|
409
|
+
create_reset_password_email do
|
410
|
+
RodauthMailer.reset_password(email_to, reset_password_email_link)
|
359
411
|
end
|
360
|
-
|
361
|
-
|
412
|
+
create_verify_account_email do
|
413
|
+
RodauthMailer.verify_account(email_to, verify_account_email_link)
|
362
414
|
end
|
363
|
-
|
364
|
-
|
415
|
+
create_verify_login_change_email do |login|
|
416
|
+
RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
|
365
417
|
end
|
366
|
-
|
367
|
-
|
418
|
+
create_password_changed_email do
|
419
|
+
RodauthMailer.password_changed(email_to)
|
368
420
|
end
|
369
|
-
#
|
370
|
-
#
|
421
|
+
# create_email_auth_email do
|
422
|
+
# RodauthMailer.email_auth(email_to, email_auth_email_link)
|
371
423
|
# end
|
372
|
-
#
|
373
|
-
#
|
424
|
+
# create_unlock_account_email do
|
425
|
+
# RodauthMailer.unlock_account(email_to, unlock_account_email_link)
|
374
426
|
# end
|
375
|
-
|
427
|
+
send_email do |email|
|
376
428
|
# 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
|
429
|
+
db.after_commit { email.deliver_later }
|
382
430
|
end
|
383
431
|
# ...
|
384
432
|
end
|
385
433
|
end
|
386
434
|
```
|
387
435
|
|
436
|
+
This approach can be used even if you're using a 3rd-party service for
|
437
|
+
transactional emails, where emails are sent via API requests instead of
|
438
|
+
SMTP. Whatever the `create_*_email` block returns will be passed to
|
439
|
+
`send_email`, so you can be creative.
|
440
|
+
|
441
|
+
### Migrations
|
442
|
+
|
443
|
+
The install generator will create a migration for tables used by the Rodauth
|
444
|
+
features enabled by default. For any additional features, you can use the
|
445
|
+
migration generator to create the corresponding tables:
|
446
|
+
|
447
|
+
```sh
|
448
|
+
$ rails generate rodauth:migration otp sms_codes recovery_codes
|
449
|
+
```
|
450
|
+
```rb
|
451
|
+
# db/migration/*_create_rodauth_otp_sms_codes_recovery_codes.rb
|
452
|
+
class CreateRodauthOtpSmsCodesRecoveryCodes < ActiveRecord::Migration
|
453
|
+
def change
|
454
|
+
create_table :account_otp_keys do |t| ... end
|
455
|
+
create_table :account_sms_codes do |t| ... end
|
456
|
+
create_table :account_recovery_codes do |t| ... end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
```
|
460
|
+
|
388
461
|
### JSON API
|
389
462
|
|
390
463
|
JSON API support in Rodauth is provided by the [JWT feature]. First you'll need
|
@@ -416,6 +489,51 @@ the configure method.
|
|
416
489
|
Make sure to store the `jwt_secret` in a secure place, such as Rails
|
417
490
|
credentials or environment variables.
|
418
491
|
|
492
|
+
### Calling controller methods
|
493
|
+
|
494
|
+
When using Rodauth before/after hooks or generally overriding your Rodauth
|
495
|
+
configuration, in some cases you might want to call methods defined on your
|
496
|
+
controllers. You can do so with `rails_controller_eval`, for example:
|
497
|
+
|
498
|
+
```rb
|
499
|
+
# app/controllers/application_controller.rb
|
500
|
+
class ApplicationController < ActionController::Base
|
501
|
+
private
|
502
|
+
def setup_tracking(account_id)
|
503
|
+
# ... some implementation ...
|
504
|
+
end
|
505
|
+
end
|
506
|
+
```
|
507
|
+
```rb
|
508
|
+
# app/lib/rodauth_app.rb
|
509
|
+
class RodauthApp < Rodauth::Rails::App
|
510
|
+
configure do
|
511
|
+
after_create_account do
|
512
|
+
rails_controller_eval { setup_tracking(account_id) }
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
```
|
517
|
+
|
518
|
+
### Rodauth instance
|
519
|
+
|
520
|
+
In some cases you might need to use Rodauth more programmatically, and perform
|
521
|
+
Rodauth operations outside of the request context. rodauth-rails gives you the
|
522
|
+
ability to retrieve the Rodauth instance:
|
523
|
+
|
524
|
+
```rb
|
525
|
+
rodauth = Rodauth::Rails.rodauth # or Rodauth::Rails.rodauth(:secondary)
|
526
|
+
|
527
|
+
rodauth.login_url #=> "https://example.com/login"
|
528
|
+
rodauth.account_from_login("user@example.com") # loads user by email
|
529
|
+
rodauth.password_match?("secret") #=> true
|
530
|
+
rodauth.setup_account_verification
|
531
|
+
rodauth.close_account
|
532
|
+
```
|
533
|
+
|
534
|
+
This Rodauth instance will be initialized with basic Rack env that allows is it
|
535
|
+
to generate URLs, using `config.action_mailer.default_url_options` options.
|
536
|
+
|
419
537
|
## How it works
|
420
538
|
|
421
539
|
### Middleware
|
@@ -460,11 +578,12 @@ end
|
|
460
578
|
The `Rodauth::Rails::App` class is a [Roda] subclass that provides Rails
|
461
579
|
integration for Rodauth:
|
462
580
|
|
463
|
-
* uses
|
464
|
-
* uses
|
581
|
+
* uses Action Dispatch flash instead of Roda's
|
582
|
+
* uses Action Dispatch CSRF protection instead of Roda's
|
465
583
|
* sets [HMAC] secret to Rails' secret key base
|
466
|
-
* uses
|
467
|
-
*
|
584
|
+
* uses Action Controller for rendering templates
|
585
|
+
* runs Action Controller callbacks & rescue handlers around Rodauth actions
|
586
|
+
* uses Action Mailer for sending emails
|
468
587
|
|
469
588
|
The `configure { ... }` method wraps configuring the Rodauth plugin, forwarding
|
470
589
|
any additional [plugin options].
|
@@ -588,6 +707,22 @@ disables the use of database functions, though you can always turn it back on.
|
|
588
707
|
use_database_authentication_functions? true
|
589
708
|
```
|
590
709
|
|
710
|
+
To create the database functions, pass the Sequel database object into the
|
711
|
+
Rodauth method for creating database functions:
|
712
|
+
|
713
|
+
```rb
|
714
|
+
# db/migrate/*_create_rodauth_database_functions.rb
|
715
|
+
class CreateRodauthDatabaseFunctions < ActiveRecord::Migration
|
716
|
+
def up
|
717
|
+
Rodauth.create_database_authentication_functions(DB)
|
718
|
+
end
|
719
|
+
|
720
|
+
def down
|
721
|
+
Rodauth.drop_database_authentication_functions(DB)
|
722
|
+
end
|
723
|
+
end
|
724
|
+
```
|
725
|
+
|
591
726
|
### Account statuses
|
592
727
|
|
593
728
|
The recommended [Rodauth migration] stores possible account status values in a
|
@@ -640,7 +775,6 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
|
|
640
775
|
|
641
776
|
[Rodauth]: https://github.com/jeremyevans/rodauth
|
642
777
|
[Sequel]: https://github.com/jeremyevans/sequel
|
643
|
-
[rendering views outside of controllers]: https://blog.bigbinary.com/2016/01/08/rendering-views-outside-of-controllers-in-rails-5.html
|
644
778
|
[feature documentation]: http://rodauth.jeremyevans.net/documentation.html
|
645
779
|
[JWT feature]: http://rodauth.jeremyevans.net/rdoc/files/doc/jwt_rdoc.html
|
646
780
|
[JWT gem]: https://github.com/jwt/ruby-jwt
|
@@ -651,3 +785,4 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
|
|
651
785
|
[Rodauth migration]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Creating+tables
|
652
786
|
[sequel-activerecord_connection]: https://github.com/janko/sequel-activerecord_connection
|
653
787
|
[plugin options]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Plugin+Options
|
788
|
+
[hmac]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC
|