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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +177 -77
  4. data/lib/generators/rodauth/install_generator.rb +28 -18
  5. data/lib/generators/rodauth/migration/account_expiration.erb +7 -0
  6. data/lib/generators/rodauth/migration/active_sessions.erb +7 -0
  7. data/lib/generators/rodauth/migration/audit_logging.erb +16 -0
  8. data/lib/generators/rodauth/migration/base.erb +19 -0
  9. data/lib/generators/rodauth/migration/disallow_password_reuse.erb +5 -0
  10. data/lib/generators/rodauth/migration/email_auth.erb +7 -0
  11. data/lib/generators/rodauth/migration/jwt_refresh.erb +7 -0
  12. data/lib/generators/rodauth/migration/lockout.erb +11 -0
  13. data/lib/generators/rodauth/migration/otp.erb +7 -0
  14. data/lib/generators/rodauth/migration/password_expiration.erb +5 -0
  15. data/lib/generators/rodauth/migration/recovery_codes.erb +6 -0
  16. data/lib/generators/rodauth/migration/remember.erb +6 -0
  17. data/lib/generators/rodauth/migration/reset_password.erb +7 -0
  18. data/lib/generators/rodauth/migration/single_session.erb +5 -0
  19. data/lib/generators/rodauth/migration/sms_codes.erb +8 -0
  20. data/lib/generators/rodauth/migration/verify_account.erb +7 -0
  21. data/lib/generators/rodauth/migration/verify_login_change.erb +7 -0
  22. data/lib/generators/rodauth/migration/webauthn.erb +12 -0
  23. data/lib/generators/rodauth/migration_generator.rb +32 -0
  24. data/lib/generators/rodauth/migration_helpers.rb +69 -0
  25. data/lib/generators/rodauth/templates/app/controllers/rodauth_controller.rb +2 -1
  26. data/lib/generators/rodauth/templates/app/lib/rodauth_app.rb +18 -18
  27. data/lib/generators/rodauth/templates/config/initializers/sequel.rb +1 -5
  28. data/lib/generators/rodauth/templates/db/migrate/create_rodauth.rb +2 -176
  29. data/lib/rodauth/rails.rb +23 -4
  30. data/lib/rodauth/rails/app.rb +3 -1
  31. data/lib/rodauth/rails/app/flash.rb +1 -1
  32. data/lib/rodauth/rails/app/middleware.rb +26 -0
  33. data/lib/rodauth/rails/feature.rb +92 -25
  34. data/lib/rodauth/rails/railtie.rb +11 -0
  35. data/lib/rodauth/rails/tasks.rake +28 -0
  36. data/lib/rodauth/rails/version.rb +1 -1
  37. data/rodauth-rails.gemspec +3 -3
  38. metadata +29 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd5d6b153ae21b024570d612aff57a2c0d6f090f2215723b25bbc362ee743c9b
4
- data.tar.gz: e6aac1fe20d00bd4c94559c74dbc56bd971da4404d086ec3193db8e06fe2a3bd
3
+ metadata.gz: 9805b35cefee7e30cc6f7190e2ace9e7ea75c20f40651eb364edafea2f2382f7
4
+ data.tar.gz: 503b821866aaf2b6aa108265ed8015869a8c8a6a73e910aa3c38b35c5a542ac1
5
5
  SHA512:
6
- metadata.gz: 83a5c386eaf39c7aa9b0536e9aed25e8a61bc069e2388bee556b28e9ee00941528fd5431199711d77a28212d281376258ecf0b914d6aa928954d8d99543b827b
7
- data.tar.gz: 815d7fee34954d2f512e4532d02bb9d183ad9bde92fc622d522c517cd9db575c8fef98c857dce81c8329cd1798481b8e2f4609390b2472d83825d393886a3576
6
+ metadata.gz: 5a3e69b6d62f20ee5bc5a13c89acd2974401830a4f0f8917cc7716c9a5ccaad021a20c0f3269a211336b648bd8eb65ae60094c90a039fa1d3968eaf322ec2e47
7
+ data.tar.gz: 567cf154e656f7062029e207d92149fa8cf2c87404d1ba72fef6327cb31f928d0bcf453a4a0d55f71740251cb74f8b6829b8c775373daec4fe638690cd702104
@@ -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.3"
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.postgres(extensions: :activerecord_connection)
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 CSRF protection.
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 Model
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
- ## Getting started
141
+ ## Usage
142
+
143
+ ### Routes
144
+
145
+ We can see the list of routes our Rodauth middleware handles:
136
146
 
137
- Let's start by adding some basic authentication navigation links to our home
138
- page:
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 links are fully functional, feel free to visit them and interact with the
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
- Let's also load the account record for authenticated requests and expose it via
156
- `#current_account`:
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 :load_account, if: -> { rodauth.authenticated? }
194
+ before_action :current_account, if: -> { rodauth.authenticated? }
162
195
 
163
196
  private
164
197
 
165
- def load_account
166
- @current_account = Account.find(rodauth.session_value)
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
- Next, we'll likely want to require authentication for certain sections/pages of
183
- our app. We can do this in our Rodauth app's routing block, which helps keep
184
- the authentication logic encapsulated:
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 at some
243
- point we'll probably want more control over the markup. For that we can run the
244
- following command:
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 don't forget to rename the Rodauth controller accordingly).
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 the authentication flow. Most email settings
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, make sure to
349
- override their `send_*_email` methods as well.
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
- send_reset_password_email do
358
- mailer_send(:reset_password, email_to, reset_password_email_link)
392
+ create_reset_password_email do
393
+ RodauthMailer.reset_password(email_to, reset_password_email_link)
359
394
  end
360
- send_verify_account_email do
361
- mailer_send(:verify_account, email_to, verify_account_email_link)
395
+ create_verify_account_email do
396
+ RodauthMailer.verify_account(email_to, verify_account_email_link)
362
397
  end
363
- send_verify_login_change_email do |login|
364
- mailer_send(:verify_login_change, login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
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
- send_password_changed_email do
367
- mailer_send(:password_changed, email_to)
401
+ create_password_changed_email do
402
+ RodauthMailer.password_changed(email_to)
368
403
  end
369
- # send_email_auth_email do
370
- # mailer_send(:email_auth, email_to, email_auth_email_link)
404
+ # create_email_auth_email do
405
+ # RodauthMailer.email_auth(email_to, email_auth_email_link)
371
406
  # end
372
- # send_unlock_account_email do
373
- # mailer_send(:unlock_account, email_to, unlock_account_email_link)
407
+ # create_unlock_account_email do
408
+ # RodauthMailer.unlock_account(email_to, unlock_account_email_link)
374
409
  # end
375
- auth_class_eval do
410
+ send_email do |email|
376
411
  # queue email delivery on the mailer after the transaction commits
377
- def mailer_send(type, *args)
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 Rails' flash instead of Roda's
433
- * uses Rails' CSRF protection instead of Roda's
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 ActionController for rendering templates
436
- * uses ActionMailer for sending emails
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