rodauth-rails 1.11.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f902ae05472454543304221221b9681c7dab3d231d6551c7e82b6c4c1570dc8
4
- data.tar.gz: b3a1948fb603be978bddea73a44b8109f4e3c76e132b2da3a8e6aad1b36f3d14
3
+ metadata.gz: 1dac2131f831b908d4bfd7a3367b310bd04b4141202b16f5e98d80e769972e32
4
+ data.tar.gz: 1742fb2bb8fb16c221a4f09d5a5f53bdc898475383f91311100571e4902c8700
5
5
  SHA512:
6
- metadata.gz: 8547335032c3e0851406932463cd62e2377c16db2145e0da6abb8a7f20745c20f9e8d54bd2b57599e335a4f9b37078cf7f1c17caa53b4dab60105c410a401469
7
- data.tar.gz: dd84bd6d57a4e8e78a6412a7ac38befa7d75ef693a6788014d383d3800a4535af71fa24239f8b0521cecc7c598766f48b2034a016a2a15235cfa9f9d2dd52761
6
+ metadata.gz: 53dc0c219dc640431b553c8e843cc728ee1aff0c57a759dfebb0254a9e885a193ab1c3dff8d6fba6ba8423abdc49e9d6e38c14125a48a82954c42942b4a16838
7
+ data.tar.gz: 07ea61d890bb27ae8cbaed4c203366ddb07c152b5f76272e2acec9865e1c7ec72472aef8b20e2a112ad831ab3bc69602f443fc80ffcb0f6b1754f1b3d317cff4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 1.12.0 (2023-10-20)
2
+
3
+ * Allow generating view template for `confirm_password` feature (igor-alexandrov)
4
+
5
+ * Forward all requests unhandled by the Rodauth app to the Rails router (@janko)
6
+
7
+ * Use `Rodauth::Model()` directly for including in generated account model (@janko)
8
+
9
+ * Set `{jwt,argon2}_secret` to `hmac_secret` on `rodauth:install` with `--{jwt,argon2}` (@janko)
10
+
11
+ * Expose `#turbo_stream` method in `Rodauth::Rails::Auth` when using turbo-rails gem (@janko)
12
+
13
+ * Add `#rails_cookies` method for accessing the Action Dispatch cookie jar (@janko)
14
+
1
15
  ## 1.11.0 (2023-08-21)
2
16
 
3
17
  * Exclude WebAuthn JS routes in `rodauth:routes`, since those stop being relevant with custom JS (@janko)
data/README.md CHANGED
@@ -15,6 +15,7 @@ Provides Rails integration for the [Rodauth] authentication framework.
15
15
 
16
16
  * [Rails Authentication with Rodauth](https://www.youtube.com/watch?v=2hDpNikacf0)
17
17
  * [Multifactor Authentication with Rodauth](https://www.youtube.com/watch?v=9ON-kgXpz2A&list=PLkGQXZLACDTGKsaRWstkHQdm2CUmT3SZ-) ([TOTP](https://youtu.be/9ON-kgXpz2A), [Recovery Codes](https://youtu.be/lkFCcE1Q5-w))
18
+ * [Add Admin Accounts](https://www.youtube.com/watch?v=N6z7AtKSpNI)
18
19
 
19
20
  📚 Articles:
20
21
 
@@ -44,11 +45,7 @@ of the advantages that stand out for me:
44
45
 
45
46
  One common concern for people coming from other Rails authentication frameworks
46
47
  is the fact that Rodauth uses [Sequel] for database interaction instead of
47
- Active Record. Sequel has powerful APIs for building advanced queries,
48
- supporting complex SQL expressions, database-agnostic date arithmetic, SQL
49
- function calls and more, all without having to drop down to raw SQL.
50
-
51
- For Rails apps using Active Record, rodauth-rails configures Sequel to [reuse
48
+ Active Record. For Rails apps using Active Record, rodauth-rails configures Sequel to [reuse
52
49
  Active Record's database connection][sequel-activerecord_connection]. This
53
50
  makes it run smoothly alongside Active Record, even allowing calling Active
54
51
  Record code from within Rodauth configuration. So, for all intents and
@@ -68,7 +65,28 @@ Next, run the install generator:
68
65
  $ rails generate rodauth:install
69
66
  ```
70
67
 
71
- This will use the `accounts` table. If you want a different table name:
68
+ This generator will create a Rodauth app and configuration with common
69
+ authentication features enabled, a database migration with tables required by
70
+ those features, a mailer with default templates, and a few other files.
71
+
72
+ Feel free to remove any features you don't need, along with their corresponding
73
+ tables. Afterwards, run the migration:
74
+
75
+ ```sh
76
+ $ rails db:migrate
77
+ ```
78
+
79
+ For your mailer to be able to generate email links, you'll need to set up
80
+ default URL options in each environment. Here is a possible configuration for
81
+ `config/environments/development.rb`:
82
+
83
+ ```rb
84
+ config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
85
+ ```
86
+
87
+ ### Install options
88
+
89
+ The install generator will use the `accounts` table by default. You can specify a different table name:
72
90
 
73
91
  ```sh
74
92
  $ rails generate rodauth:install users
@@ -90,25 +108,6 @@ $ rails generate rodauth:install --argon2
90
108
  $ bundle add argon2
91
109
  ```
92
110
 
93
- This generator will create a Rodauth app and configuration with common
94
- authentication features enabled, a database migration with tables required by
95
- those features, a mailer with default templates, and a few other files.
96
-
97
- Feel free to remove any features you don't need, along with their corresponding
98
- tables. Afterwards, run the migration:
99
-
100
- ```sh
101
- $ rails db:migrate
102
- ```
103
-
104
- For your mailer to be able to generate email links, you'll need to set up
105
- default URL options in each environment. Here is a possible configuration for
106
- `config/environments/development.rb`:
107
-
108
- ```rb
109
- config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
110
- ```
111
-
112
111
  ## Usage
113
112
 
114
113
  The Rodauth app will be called for each request before it reaches the Rails
@@ -153,7 +152,7 @@ navigation header:
153
152
 
154
153
  ```erb
155
154
  <% if rodauth.logged_in? %>
156
- <%= link_to "Sign out", rodauth.logout_path, method: :post %>
155
+ <%= link_to "Sign out", rodauth.logout_path, data: { turbo_method: :post } %>
157
156
  <% else %>
158
157
  <%= link_to "Sign in", rodauth.login_path %>
159
158
  <%= link_to "Sign up", rodauth.create_account_path %>
@@ -181,28 +180,18 @@ class ApplicationController < ActionController::Base
181
180
  end
182
181
  ```
183
182
 
184
- ```rb
185
- current_account #=> #<Account id=123 email="user@example.com">
186
- current_account.email #=> "user@example.com"
187
- ```
188
-
189
183
  ### Requiring authentication
190
184
 
191
- You'll likely want to require authentication for certain parts of your app,
192
- redirecting the user to the login page if they're not logged in. You can do this
193
- in your Rodauth app's routing block, which helps keep the authentication logic
194
- encapsulated:
185
+ You can require authentication for routes at the middleware level in in your Rodauth
186
+ app's routing block, which helps keep the authentication logic encapsulated:
195
187
 
196
188
  ```rb
197
189
  # app/misc/rodauth_app.rb
198
190
  class RodauthApp < Rodauth::Rails::App
199
- # ...
200
191
  route do |r|
201
- # ...
202
192
  r.rodauth # route rodauth requests
203
193
 
204
- # require authentication for /dashboard/* routes
205
- if r.path.start_with?("/dashboard")
194
+ if r.path.start_with?("/dashboard") # /dashboard/* routes
206
195
  rodauth.require_account # redirect to login page if not authenticated
207
196
  end
208
197
  end
@@ -212,7 +201,6 @@ end
212
201
  You can also require authentication at the controller layer:
213
202
 
214
203
  ```rb
215
- # app/controllers/application_controller.rb
216
204
  class ApplicationController < ActionController::Base
217
205
  private
218
206
 
@@ -222,68 +210,46 @@ class ApplicationController < ActionController::Base
222
210
  end
223
211
  ```
224
212
  ```rb
225
- # app/controllers/dashboard_controller.rb
226
213
  class DashboardController < ApplicationController
227
214
  before_action :authenticate
228
215
  end
229
216
  ```
230
217
 
231
- #### Routing constraints
232
-
233
- In some cases it makes sense to require authentication at the Rails router
234
- level. You can do this via the built-in `authenticated` routing constraint:
218
+ Additionally, routes can be authenticated at the Rails router level:
235
219
 
236
220
  ```rb
237
221
  # config/routes.rb
238
222
  Rails.application.routes.draw do
239
223
  constraints Rodauth::Rails.authenticate do
240
- # ... authenticated routes ...
224
+ # ... these routes will require authentication ...
241
225
  end
242
- end
243
- ```
244
-
245
- If you want additional conditions, you can pass in a block, which is
246
- called with the Rodauth instance:
247
226
 
248
- ```rb
249
- # config/routes.rb
250
- Rails.application.routes.draw do
251
- # require multifactor authentication to be setup
252
227
  constraints Rodauth::Rails.authenticate { |rodauth| rodauth.uses_two_factor_authentication? } do
253
- # ...
228
+ # ... these routes will be available only if 2FA is setup ...
254
229
  end
255
- end
256
- ```
257
230
 
258
- You can specify a different Rodauth configuration by passing the configuration name:
259
-
260
- ```rb
261
- # config/routes.rb
262
- Rails.application.routes.draw do
263
231
  constraints Rodauth::Rails.authenticate(:admin) do
264
- # ...
232
+ # ... these routes will be authenticated with secondary "admin" configuration ...
265
233
  end
266
- end
267
- ```
268
234
 
269
- If you need something more custom, you can always create the routing constraint
270
- manually:
271
-
272
- ```rb
273
- # config/routes.rb
274
- Rails.application.routes.draw do
275
235
  constraints -> (r) { !r.env["rodauth"].logged_in? } do # or env["rodauth.admin"]
276
- # routes when the user is not logged in
236
+ # ... these routes will be available only if not authenticated ...
277
237
  end
278
238
  end
279
239
  ```
280
240
 
281
241
  ### Controller
282
242
 
283
- Your Rodauth configuration is connected to a Rails controller (`RodauthController` by default), and
284
- it automatically executes any callbacks and rescue handlers defined on it (or the parent controller)
285
- around Rodauth endpoints.
243
+ Your Rodauth configuration is linked to a Rails controller, which is primarily used to render views and handle CSRF protection, but will also execute any callbacks and rescue handlers defined on it around Rodauth endpoints.
286
244
 
245
+ ```rb
246
+ # app/misc/rodauth_main.rb
247
+ class RodauthMain < Rodauth::Rails::Auth
248
+ configure do
249
+ rails_controller { RodauthController }
250
+ end
251
+ end
252
+ ```
287
253
  ```rb
288
254
  class RodauthController < ApplicationController
289
255
  before_action :set_locale # executes before Rodauth endpoints
@@ -291,45 +257,31 @@ class RodauthController < ApplicationController
291
257
  end
292
258
  ```
293
259
 
294
- #### Calling controller methods
260
+ Various methods are available in your Rodauth configuration to bridge the gap with the controller:
295
261
 
296
- You can call any controller methods from your Rodauth configuration via `rails_controller_eval`:
297
-
298
- ```rb
299
- # app/controllers/application_controller.rb
300
- class ApplicationController < ActionController::Base
301
- private
302
- def setup_tracking(account_id)
303
- # ... some implementation ...
304
- end
305
- end
306
- ```
307
262
  ```rb
308
- # app/misc/rodauth_main.rb
309
263
  class RodauthMain < Rodauth::Rails::Auth
310
264
  configure do
265
+ # calling methods on the controller:
311
266
  after_create_account do
312
- rails_controller_eval { setup_tracking(account_id) }
267
+ rails_controller_eval { some_controller_method(account_id) }
313
268
  end
314
- end
315
- end
316
- ```
317
269
 
318
- ### Rails URL helpers
270
+ # accessing Rails URL helpers:
271
+ login_redirect { rails_routes.dashboard_path }
319
272
 
320
- Inside Rodauth configuration and the `route` block you can access Rails route
321
- helpers through `#rails_routes`:
273
+ # accessing Rails request object:
274
+ after_change_password do
275
+ if rails_request.format.turbo_stream?
276
+ return_response rails_render(turbo_stream: [turbo_stream.replace(...)])
277
+ end
278
+ end
322
279
 
323
- ```rb
324
- # app/misc/rodauth_main.rb
325
- class RodauthMain < Rodauth::Rails::Auth
326
- configure do
327
- login_redirect { rails_routes.activity_path }
328
- change_password_redirect { rails_routes.profile_path }
329
- change_login_redirect { rails_routes.profile_path }
280
+ # accessing Rails cookies:
281
+ after_login { rails_cookies.permanent[:last_account_id] = account_id }
330
282
  end
331
283
  end
332
- ```
284
+ ```
333
285
 
334
286
  ## Views
335
287
 
@@ -338,97 +290,29 @@ you'll want to start editing the markup. You can run the following command to
338
290
  copy Rodauth templates into your Rails app:
339
291
 
340
292
  ```sh
341
- $ rails generate rodauth:views # bootstrap views
342
- # or
343
- $ rails generate rodauth:views --css=tailwind # tailwind views (requires @tailwindcss/forms plugin)
293
+ $ rails generate rodauth:views
344
294
  ```
345
295
 
346
296
  This will generate views for Rodauth features you have currently enabled into
347
- the `app/views/rodauth` directory, provided that `RodauthController` is set for
348
- the main configuration.
297
+ the `app/views/rodauth` directory (provided that `RodauthController` is set for
298
+ the main configuration).
349
299
 
350
- You can pass a list of Rodauth features to the generator to create views for
351
- these features (this will not remove any existing views):
300
+ The generator accepts various options:
352
301
 
353
302
  ```sh
354
- $ rails generate rodauth:views login create_account lockout otp
355
- ```
303
+ # generate views with Tailwind markup (requires @tailwindcss/forms plugin)
304
+ $ rails generate rodauth:views --css=tailwind
356
305
 
357
- Or you can generate views for all features:
306
+ # specify Rodauth features to generate views for
307
+ $ rails generate rodauth:views login create_account lockout otp
358
308
 
359
- ```sh
309
+ # generate views for all Rodauth features
360
310
  $ rails generate rodauth:views --all
361
- ```
362
-
363
- Use `--name` to generate views for a different Rodauth configuration:
364
311
 
365
- ```sh
312
+ # specify a different Rodauth configuration
366
313
  $ rails generate rodauth:views webauthn two_factor_base --name admin
367
314
  ```
368
315
 
369
- ### Page titles
370
-
371
- The generated configuration sets `title_instance_variable` to make page titles
372
- available in your views via `@page_title` instance variable, which you can then
373
- use in your layout:
374
-
375
- ```rb
376
- # app/misc/rodauth_main.rb
377
- class RodauthMain < Rodauth::Rails::Auth
378
- configure do
379
- title_instance_variable :@page_title
380
- end
381
- end
382
- ```
383
- ```erb
384
- <!-- app/views/layouts/application.html.erb -->
385
- <!DOCTYPE html>
386
- <html>
387
- <head>
388
- <title><%= @page_title || "Default title" %></title>
389
- <!-- ... -->
390
- </head>
391
- <!-- ... -->
392
- </html>
393
- ```
394
-
395
- ### Layout
396
-
397
- To use different layouts for different Rodauth views, you can compare the
398
- request path in the layout method:
399
-
400
- ```rb
401
- # app/controllers/rodauth_controller.rb
402
- class RodauthController < ApplicationController
403
- layout :rodauth_layout
404
-
405
- private
406
-
407
- def rodauth_layout
408
- case request.path
409
- when rodauth.login_path,
410
- rodauth.create_account_path,
411
- rodauth.verify_account_path,
412
- rodauth.verify_account_resend_path,
413
- rodauth.reset_password_path,
414
- rodauth.reset_password_request_path
415
- "authentication"
416
- else
417
- "dashboard"
418
- end
419
- end
420
- end
421
- ```
422
-
423
- ### Turbo
424
-
425
- [Turbo] has been disabled by default on all built-in and generated view
426
- templates, because some Rodauth actions (multi-phase login, adding recovery
427
- codes) aren't Turbo-compatible, as they return 200 responses on POST requests.
428
-
429
- That being said, most of Rodauth *is* Turbo-compatible, so feel free to enable
430
- Turbo for actions where you want to use it.
431
-
432
316
  ## Mailer
433
317
 
434
318
  The install generator will create `RodauthMailer` with default email templates,
@@ -492,8 +376,6 @@ class CreateRodauthOtpSmsCodesRecoveryCodes < ActiveRecord::Migration
492
376
  end
493
377
  ```
494
378
 
495
- ### Table prefix
496
-
497
379
  If you're storing account records in a table other than `accounts`, you'll want
498
380
  to specify the appropriate table prefix when generating new migrations:
499
381
 
@@ -516,15 +398,13 @@ class CreateRodauthUserBaseActiveSessions < ActiveRecord::Migration
516
398
  end
517
399
  ```
518
400
 
519
- ### Custom migration name
520
-
521
401
  You can change the default migration name:
522
402
 
523
403
  ```sh
524
404
  $ rails generate rodauth:migration email_auth --name create_account_email_auth_keys
525
405
  ```
526
406
  ```rb
527
- # db/migration/*_create_account_email_auth_keys
407
+ # db/migration/*_create_account_email_auth_keys.rb
528
408
  class CreateAccountEmailAuthKeys < ActiveRecord::Migration
529
409
  def change
530
410
  create_table :account_email_auth_keys do |t| ... end
@@ -540,7 +420,7 @@ tables used by enabled authentication features.
540
420
 
541
421
  ```rb
542
422
  class Account < ActiveRecord::Base # Sequel::Model
543
- include Rodauth::Rails.model # or Rodauth::Rails.model(:admin)
423
+ include Rodauth::Model(RodauthMain)
544
424
  end
545
425
  ```
546
426
  ```rb
@@ -573,6 +453,10 @@ class RodauthApp < Rodauth::Rails::App
573
453
  route do |r|
574
454
  r.rodauth # route primary rodauth requests
575
455
  r.rodauth(:admin) # route secondary rodauth requests
456
+
457
+ if request.path.start_with?("/admin")
458
+ rodauth(:admin).require_account
459
+ end
576
460
  end
577
461
  end
578
462
  ```
@@ -599,6 +483,7 @@ end
599
483
  Then in your application you can reference the secondary Rodauth instance:
600
484
 
601
485
  ```rb
486
+ rodauth(:admin).authenticated? # checks "admin_account_id" session value
602
487
  rodauth(:admin).login_path #=> "/admin/login"
603
488
  ```
604
489
 
@@ -608,66 +493,24 @@ that. Note that you can also [share configuration via inheritance][inheritance].
608
493
 
609
494
  ## Outside of a request
610
495
 
611
- ### Calling actions
612
-
613
- In some cases you might need to use Rodauth more programmatically. If you want
614
- to perform authentication operations outside of request context, Rodauth ships
615
- with the [internal_request] feature just for that.
496
+ The [internal_request] and [path_class_methods] features are supported, with defaults taken from `config.action_mailer.default_url_options`.
616
497
 
617
498
  ```rb
618
- # app/misc/rodauth_main.rb
619
- class RodauthMain < Rodauth::Rails::Auth
620
- configure do
621
- enable :internal_request
622
- end
623
- end
624
- ```
625
- ```rb
626
- # primary configuration
499
+ # internal requests
627
500
  RodauthApp.rodauth.create_account(login: "user@example.com", password: "secret123")
628
- RodauthApp.rodauth.verify_account(account_login: "user@example.com")
629
-
630
- # secondary configuration
631
- RodauthApp.rodauth(:admin).close_account(account_login: "user@example.com")
632
- ```
633
-
634
- ### Generating URLs
635
-
636
- For generating authentication URLs outside of a request use the
637
- [path_class_methods] plugin:
638
-
639
- ```rb
640
- # app/misc/rodauth_main.rb
641
- class RodauthMain < Rodauth::Rails::Auth
642
- configure do
643
- enable :path_class_methods
644
- create_account_route "register"
645
- end
646
- end
647
- ```
648
- ```rb
649
- # primary configuration
650
- RodauthApp.rodauth.create_account_path # => "/register"
651
- RodauthApp.rodauth.verify_account_url(key: "abc123") #=> "https://example.com/verify-account?key=abc123"
501
+ RodauthApp.rodauth(:admin).verify_account(account_login: "admin@example.com")
652
502
 
653
- # secondary configuration
654
- RodauthApp.rodauth(:admin).close_account_path(foo: "bar") #=> "/admin/close-account?foo=bar"
503
+ # path and URL methods
504
+ RodauthApp.rodauth.close_account_path #=> "/close-account"
505
+ RodauthApp.rodauth(:admin).otp_setup_url #=> "http://localhost:3000/admin/otp-setup"
655
506
  ```
656
507
 
657
508
  ### Calling instance methods
658
509
 
659
510
  If you need to access Rodauth methods not exposed as internal requests, you can
660
- use `Rodauth::Rails.rodauth` to retrieve the Rodauth instance used by the
661
- internal_request feature:
511
+ use `Rodauth::Rails.rodauth` to retrieve the Rodauth instance (this requires enabling
512
+ the internal_request feature):
662
513
 
663
- ```rb
664
- # app/misc/rodauth_main.rb
665
- class RodauthMain < Rodauth::Rails::Auth
666
- configure do
667
- enable :internal_request # this is required
668
- end
669
- end
670
- ```
671
514
  ```rb
672
515
  account = Account.find_by!(email: "user@example.com")
673
516
  rodauth = Rodauth::Rails.rodauth(account: account) #=> #<RodauthMain::InternalRequest ...>
@@ -693,8 +536,12 @@ Rodauth::Rails.rodauth(:admin, params: { "param" => "value" })
693
536
 
694
537
  ### Using as a library
695
538
 
696
- Rodauth offers a `Rodauth.lib` method for configuring Rodauth so that it can be used as a library, instead of routing requests (see [internal_request] feature). This gem provides a `Rodauth::Rails.lib` counterpart that does the same but with Rails integration:
539
+ Rodauth offers a [`Rodauth.lib`][library] method for when you want to use it as a library (via [internal requests][internal_request]), as opposed to having it route requests. This gem provides a `Rodauth::Rails.lib` counterpart that does the same but with Rails integration:
697
540
 
541
+ ```rb
542
+ # skip require on boot to avoid inserting Rodauth middleware
543
+ gem "rodauth-rails", require: false
544
+ ```
698
545
  ```rb
699
546
  # app/misc/rodauth_main.rb
700
547
  require "rodauth/rails"
@@ -712,23 +559,6 @@ RodauthMain.login(login: "email@example.com", password: "secret123")
712
559
  RodauthMain.close_account(account_login: "email@example.com")
713
560
  ```
714
561
 
715
- Note that you'll want to skip requiring `rodauth-rails` on Rails boot, to avoid it automatically inserting the Rodauth middleware, and remove some unnecessary files generated by the install generator.
716
-
717
- ```rb
718
- # Gemfile
719
- gem "rodauth-rails", require: false
720
- ```
721
- ```sh
722
- $ rm config/initializers/rodauth.rb app/misc/rodauth_app.rb app/controllers/rodauth_controller.rb
723
- ```
724
-
725
- The `Rodauth::Rails.lib` call will forward any Rodauth [plugin options] passed to it:
726
-
727
- ```rb
728
- # skips loading Roda render plugin and Tilt gem (used for rendering built-in templates)
729
- Rodauth::Rails.lib(render: false) { ... }
730
- ```
731
-
732
562
  ## Testing
733
563
 
734
564
  For system and integration tests, which run the whole middleware stack,
@@ -790,10 +620,7 @@ For more examples and information about testing with rodauth, see
790
620
 
791
621
  ## Configuring
792
622
 
793
- ### Configuration methods
794
-
795
- The `rails` feature rodauth-rails loads provides the following configuration
796
- methods:
623
+ The `rails` feature rodauth-rails loads provides the following configuration methods:
797
624
 
798
625
  | Name | Description |
799
626
  | :---- | :---------- |
@@ -806,70 +633,6 @@ methods:
806
633
  | `rails_controller` | Controller class to use for rendering and CSRF protection. |
807
634
  | `rails_account_model` | Model class connected with the accounts table. |
808
635
 
809
- ```rb
810
- class RodauthMain < Rodauth::Rails::Auth
811
- configure do
812
- rails_controller { Authentication::RodauthController }
813
- rails_account_model { Authentication::Account }
814
- end
815
- end
816
- ```
817
-
818
- For the list of configuration methods provided by Rodauth, see the [feature
819
- documentation].
820
-
821
- ### Defining custom methods
822
-
823
- All Rodauth configuration methods are just syntax sugar for defining instance
824
- methods on the auth class. You can also define your own custom methods:
825
-
826
- ```rb
827
- class RodauthMain < Rodauth::Rails::Auth
828
- configure do
829
- password_match? { |password| ldap_valid?(password) }
830
- end
831
-
832
- def admin?
833
- rails_account.admin?
834
- end
835
-
836
- private
837
-
838
- def ldap_valid?(password)
839
- SimpleLdapAuthenticator.valid?(account[:email], password)
840
- end
841
- end
842
- ```
843
- ```rb
844
- rodauth.admin? #=> true
845
- ```
846
-
847
- ### Single-file configuration
848
-
849
- If you would prefer, you can have all your Rodauth logic contained inside the
850
- Rodauth app class:
851
-
852
- ```rb
853
- # app/misc/rodauth_app.rb
854
- class RodauthApp < Rodauth::Rails::App
855
- # primary configuration
856
- configure do
857
- enable :login, :logout, :create_account, :verify_account
858
- # ...
859
- end
860
-
861
- # secondary configuration
862
- configure(:admin) do
863
- enable :email_auth, :single_session
864
- # ...
865
- end
866
-
867
- route do |r|
868
- # ...
869
- end
870
- end
871
- ```
872
-
873
636
  ### Manually inserting middleware
874
637
 
875
638
  You can choose to insert the Rodauth middleware somewhere earlier than
@@ -888,7 +651,7 @@ Rails.application.config.middleware.insert_before AnotherMiddleware, Rodauth::Ra
888
651
  ### Rack middleware
889
652
 
890
653
  The railtie inserts [`Rodauth::Rails::Middleware`](/lib/rodauth/rails/middleware.rb)
891
- at the end of the middleware stack, which calls your Rodauth app around each request.
654
+ at the end of the middleware stack, which is just a wrapper around your Rodauth app.
892
655
 
893
656
  ```sh
894
657
  $ rails middleware
@@ -897,34 +660,15 @@ $ rails middleware
897
660
  # run MyApp::Application.routes
898
661
  ```
899
662
 
900
- The middleware retrieves the Rodauth app via `Rodauth::Rails.app`, which is
901
- specified as a string to keep the class autoloadable and reloadable in
902
- development.
903
-
904
- ```rb
905
- Rodauth::Rails.configure do |config|
906
- config.app = "RodauthApp"
907
- end
908
- ```
909
-
910
- In addition to Zeitwerk compatibility, this extra layer catches Rodauth redirects
911
- that happen on the controller level (e.g. when calling
912
- `rodauth.require_account` in a `before_action` filter).
913
-
914
663
  ### Roda app
915
664
 
916
665
  The [`Rodauth::Rails::App`](/lib/rodauth/rails/app.rb) class is a [Roda]
917
- subclass that provides a convenience layer for Rodauth:
918
-
919
- * uses Action Dispatch flash messages
920
- * provides syntax sugar for loading the rodauth plugin
921
- * saves Rodauth object(s) to Rack env hash
922
- * propagates edited headers to Rails responses
666
+ subclass that provides a convenience layer over Rodauth.
923
667
 
924
668
  #### Configure block
925
669
 
926
- The `configure` call loads the rodauth plugin. By convention, it receives an
927
- auth class and configuration name as positional arguments (forwarded as
670
+ The `configure` call is a wrapper around `plugin :rodauth`. By convention, it receives an
671
+ auth class and configuration name as positional arguments (which get converted into
928
672
  `:auth_class` and `:name` plugin options), a block for anonymous auth classes,
929
673
  and also accepts any additional plugin options.
930
674
 
@@ -956,29 +700,21 @@ class RodauthApp < Rodauth::Rails::App
956
700
  end
957
701
  ```
958
702
 
959
- #### Routing prefix
703
+ #### Rack env
960
704
 
961
- If you use a routing prefix, you don't need to add a call to `r.on` like with
962
- vanilla Rodauth, as `r.rodauth` has been modified to automatically route the
963
- prefix.
705
+ The app sets Rodauth objects for each registered configuration in the Rack env,
706
+ so that they're accessible downstream by the Rails router, controllers and views:
964
707
 
965
708
  ```rb
966
- class RodauthApp < Rodauth::Rails::App
967
- configure do
968
- prefix "/user"
969
- end
970
-
971
- route do |r|
972
- r.rodauth # no need to wrap with `r.on("user") { ... }`
973
- end
974
- end
709
+ request.env["rodauth"] #=> #<RodauthMain>
710
+ request.env["rodauth.admin"] #=> #<RodauthAdmin> (if using multiple configurations)
975
711
  ```
976
712
 
977
713
  ### Auth class
978
714
 
979
715
  The [`Rodauth::Rails::Auth`](/lib/rodauth/rails/auth.rb) class is a subclass of
980
716
  `Rodauth::Auth`, which preloads the `rails` rodauth feature, sets [HMAC] secret to
981
- Rails' secret key base, and modifies some [configuration defaults](#rodauth-defaults).
717
+ Rails' secret key base, and modifies some [configuration defaults][restoring defaults].
982
718
 
983
719
  ```rb
984
720
  class RodauthMain < Rodauth::Rails::Auth
@@ -1000,128 +736,6 @@ The [`rails`](/lib/rodauth/rails/feature.rb) Rodauth feature loaded by
1000
736
  * uses Action Controller instrumentation around Rodauth requests
1001
737
  * uses Action Mailer's default URL options when calling Rodauth outside of a request
1002
738
 
1003
- ### Controller
1004
-
1005
- The Rodauth app stores the `Rodauth::Rails::Auth` instances in the Rack env
1006
- hash, which is then available in your Rails app:
1007
-
1008
- ```rb
1009
- request.env["rodauth"] #=> #<RodauthMain>
1010
- request.env["rodauth.admin"] #=> #<RodauthAdmin> (if using multiple configurations)
1011
- ```
1012
-
1013
- For convenience, this object can be accessed via the `#rodauth` method in views
1014
- and controllers:
1015
-
1016
- ```rb
1017
- class MyController < ApplicationController
1018
- def my_action
1019
- rodauth #=> #<RodauthMain>
1020
- rodauth(:admin) #=> #<RodauthAdmin> (if using multiple configurations)
1021
- end
1022
- end
1023
- ```
1024
- ```erb
1025
- <% rodauth #=> #<RodauthMain> %>
1026
- <% rodauth(:admin) #=> #<RodauthAdmin> (if using multiple configurations) %>
1027
- ```
1028
-
1029
- ## Rodauth defaults
1030
-
1031
- rodauth-rails changes some of the default Rodauth settings for easier setup:
1032
-
1033
- ### Database functions
1034
-
1035
- By default, on PostgreSQL, MySQL, and Microsoft SQL Server Rodauth uses
1036
- database functions to access password hashes, with the user running the
1037
- application unable to get direct access to password hashes. This reduces the
1038
- risk of an attacker being able to access password hashes and use them to attack
1039
- other sites.
1040
-
1041
- While this is useful additional security, it is also more complex to set up and
1042
- to reason about, as it requires having two different database users and making
1043
- sure the correct migration is run for the correct user.
1044
-
1045
- To keep with Rails' "convention over configuration" doctrine, rodauth-rails
1046
- disables the use of database functions, though you can always turn it back on.
1047
-
1048
- ```rb
1049
- use_database_authentication_functions? true
1050
- ```
1051
-
1052
- To create the database functions, pass the Sequel database object into the
1053
- Rodauth method for creating database functions:
1054
-
1055
- ```rb
1056
- # db/migrate/*_create_rodauth_database_functions.rb
1057
- require "rodauth/migrations"
1058
-
1059
- class CreateRodauthDatabaseFunctions < ActiveRecord::Migration
1060
- def up
1061
- Rodauth.create_database_authentication_functions(db)
1062
- end
1063
-
1064
- def down
1065
- Rodauth.drop_database_authentication_functions(db)
1066
- end
1067
-
1068
- private
1069
-
1070
- def db
1071
- RodauthMain.allocate.db
1072
- end
1073
- end
1074
- ```
1075
-
1076
- ### Account statuses
1077
-
1078
- The recommended [Rodauth migration] stores possible account status values in a
1079
- separate table, and creates a foreign key on the accounts table, which ensures
1080
- only a valid status value will be persisted. Unfortunately, this doesn't work
1081
- when the database is restored from the schema file, in which case the account
1082
- statuses table will be empty. This happens in tests by default, but it's also
1083
- not unusual to do it in development.
1084
-
1085
- To address this, rodauth-rails uses a `status` column without a separate table.
1086
- If you're worried about invalid status values creeping in, you may use enums
1087
- instead. Alternatively, you can always go back to the setup recommended by
1088
- Rodauth.
1089
-
1090
- ```rb
1091
- # in the migration:
1092
- create_table :account_statuses do |t|
1093
- t.string :name, null: false, unique: true
1094
- end
1095
- execute "INSERT INTO account_statuses (id, name) VALUES (1, 'Unverified'), (2, 'Verified'), (3, 'Closed')"
1096
-
1097
- create_table :accounts do |t|
1098
- # ...
1099
- t.references :status, foreign_key: { to_table: :account_statuses }, null: false, default: 1
1100
- # ...
1101
- end
1102
- ```
1103
- ```diff
1104
- class RodauthMain < Rodauth::Rails::Auth
1105
- configure do
1106
- # ...
1107
- - account_status_column :status
1108
- # ...
1109
- end
1110
- end
1111
- ```
1112
-
1113
- ### Deadline values
1114
-
1115
- To simplify changes to the database schema, rodauth-rails configures Rodauth
1116
- to set deadline values for various features in Ruby, instead of relying on
1117
- the database to set default column values.
1118
-
1119
- You can easily change this back:
1120
-
1121
- ```rb
1122
- set_deadline_values? false
1123
- ```
1124
-
1125
739
  ## License
1126
740
 
1127
741
  The gem is available as open source under the terms of the [MIT
@@ -1135,12 +749,10 @@ conduct](CODE_OF_CONDUCT.md).
1135
749
 
1136
750
  [Rodauth]: https://github.com/jeremyevans/rodauth
1137
751
  [Sequel]: https://github.com/jeremyevans/sequel
1138
- [feature documentation]: http://rodauth.jeremyevans.net/documentation.html
1139
752
  [Bootstrap]: https://getbootstrap.com/
1140
753
  [Roda]: http://roda.jeremyevans.net/
1141
754
  [HMAC]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC
1142
755
  [database authentication functions]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Password+Hash+Access+Via+Database+Functions
1143
- [Rodauth migration]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Creating+tables
1144
756
  [sequel-activerecord_connection]: https://github.com/janko/sequel-activerecord_connection
1145
757
  [plugin options]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Plugin+Options
1146
758
  [hmac]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC
@@ -1169,3 +781,5 @@ conduct](CODE_OF_CONDUCT.md).
1169
781
  [rodauth-model]: https://github.com/janko/rodauth-model
1170
782
  [JSON API]: https://github.com/janko/rodauth-rails/wiki/JSON-API
1171
783
  [inheritance]: http://rodauth.jeremyevans.net/rdoc/files/doc/guides/share_configuration_rdoc.html
784
+ [library]: https://github.com/jeremyevans/rodauth#label-Using+Rodauth+as+a+Library
785
+ [restoring defaults]: https://github.com/janko/rodauth-rails/wiki/Restoring-Rodauth-Defaults
@@ -46,7 +46,7 @@ class RodauthMain < Rodauth::Rails::Auth
46
46
  <% if argon2? -%>
47
47
 
48
48
  # Use a rotatable password pepper when hashing passwords with Argon2.
49
- # argon2_secret "<SECRET_KEY>"
49
+ # argon2_secret { hmac_secret }
50
50
 
51
51
  # Since we're using argon2, prevent loading the bcrypt gem to save memory.
52
52
  require_bcrypt? false
@@ -54,7 +54,7 @@ class RodauthMain < Rodauth::Rails::Auth
54
54
  <% if jwt? -%>
55
55
 
56
56
  # Set JWT secret, which is used to cryptographically protect the token.
57
- jwt_secret "<%= SecureRandom.hex(64) %>"
57
+ jwt_secret { hmac_secret }
58
58
  <% end -%>
59
59
  <% if json? || jwt? -%>
60
60
 
@@ -72,7 +72,7 @@ class RodauthMain < Rodauth::Rails::Auth
72
72
  # Specify the controller used for view rendering, CSRF, and callbacks.
73
73
  rails_controller { RodauthController }
74
74
 
75
- # Set in Rodauth controller instance with the title of the current page.
75
+ # Make built-in page titles accessible in your views via an instance variable.
76
76
  title_instance_variable :@page_title
77
77
 
78
78
  # Store account status in an integer column without foreign key constraint.
@@ -1,6 +1,6 @@
1
1
  <% if defined?(ActiveRecord::Railtie) -%>
2
2
  class <%= table_prefix.camelize %> < ApplicationRecord
3
- include Rodauth::Rails.model
3
+ include Rodauth::Model(RodauthMain)
4
4
  <% if ActiveRecord.version >= Gem::Version.new("7.0") -%>
5
5
  enum :status, unverified: 1, verified: 2, closed: 3
6
6
  <% else -%>
@@ -9,7 +9,7 @@ class <%= table_prefix.camelize %> < ApplicationRecord
9
9
  end
10
10
  <% else -%>
11
11
  class <%= table_prefix.camelize %> < Sequel::Model
12
- include Rodauth::Rails.model
12
+ include Rodauth::Model(RodauthMain)
13
13
  plugin :enum
14
14
  enum :status, unverified: 1, verified: 2, closed: 3
15
15
  end
@@ -41,6 +41,7 @@ module Rodauth
41
41
  recovery_codes: %w[recovery_codes add_recovery_codes recovery_auth],
42
42
  webauthn: %w[webauthn_setup webauthn_auth webauthn_remove],
43
43
  webauthn_autofill: %w[webauthn_autofill],
44
+ confirm_password: %w[confirm_password],
44
45
  }
45
46
 
46
47
  def create_views
@@ -5,7 +5,7 @@ module Rodauth
5
5
  module Rails
6
6
  # The superclass for creating a Rodauth middleware.
7
7
  class App < Roda
8
- plugin :middleware, forward_response_headers: true do |middleware|
8
+ plugin :middleware, forward_response_headers: true, next_if_not_found: true do |middleware|
9
9
  middleware.class_eval do
10
10
  def self.inspect
11
11
  "#{superclass}::Middleware"
@@ -54,6 +54,10 @@ module Rodauth
54
54
  ::Rails.application.routes.url_helpers
55
55
  end
56
56
 
57
+ def rails_cookies
58
+ rails_request.cookie_jar
59
+ end
60
+
57
61
  def rails_request
58
62
  ActionDispatch::Request.new(env)
59
63
  end
@@ -77,7 +81,7 @@ module Rodauth
77
81
  if prefix.present? && remaining_path == path_info
78
82
  on prefix[1..-1] do
79
83
  super
80
- pass # forward other {prefix}/* requests downstream
84
+ pass
81
85
  end
82
86
  else
83
87
  super
@@ -47,7 +47,7 @@ module Rodauth
47
47
  raise Error, "cannot infer account model, please set `rails_account_model` in your rodauth configuration"
48
48
  end
49
49
 
50
- delegate :rails_routes, :rails_request, to: :scope
50
+ delegate :rails_routes, :rails_cookies, :rails_request, to: :scope
51
51
 
52
52
  private
53
53
 
@@ -28,6 +28,12 @@ module Rodauth
28
28
  super.html_safe
29
29
  end
30
30
 
31
+ if defined?(::Turbo)
32
+ def turbo_stream
33
+ rails_controller_instance.send(:turbo_stream)
34
+ end
35
+ end
36
+
31
37
  private
32
38
 
33
39
  # Calls the Rails renderer, returning nil if a template is missing.
@@ -1,5 +1,5 @@
1
1
  module Rodauth
2
2
  module Rails
3
- VERSION = "1.11.0"
3
+ VERSION = "1.12.0"
4
4
  end
5
5
  end
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.add_dependency "railties", ">= 5.0", "< 8"
20
20
  spec.add_dependency "rodauth", "~> 2.30"
21
- spec.add_dependency "roda", "~> 3.55"
21
+ spec.add_dependency "roda", "~> 3.73"
22
22
  spec.add_dependency "sequel-activerecord_connection", "~> 1.1"
23
23
  spec.add_dependency "rodauth-model", "~> 0.2"
24
24
  spec.add_dependency "tilt"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.0
4
+ version: 1.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-21 00:00:00.000000000 Z
11
+ date: 2023-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '3.55'
53
+ version: '3.73'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '3.55'
60
+ version: '3.73'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: sequel-activerecord_connection
63
63
  requirement: !ruby/object:Gem::Requirement