rodauth-rails 0.5.0 → 0.8.1

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: f0d00b7ad2f6198fff3a5cc3c720c6f30d9296898e3fd764ddf7408e36232a6d
4
- data.tar.gz: 9ba008116fc5521c98ed62dda5b1f6b2eccd733d06ccb0a2c5b9b4db8df94539
3
+ metadata.gz: a3f1fd01ddd20052bd15e3c822ff44ca4a6f5d425dd18892ecffa34146364437
4
+ data.tar.gz: 8907b8616edf882d21ebff69b461cc12dae737f8ec34bdaf5c2d58ac5cc9b632
5
5
  SHA512:
6
- metadata.gz: 848873e599cfb8dc8a5d274ac5fec5987cf4c895c77757a4b21529ddcd9a635ba8086c037f55c55ef097ae926549234e5abebb97a5300f0ead6118927d737d91
7
- data.tar.gz: aa75fb48217e79c40000cf1f226f36a65fdffdcb764233572ae45341b7ab9dd2f1d8f8470e593d8260495962b1b5c352e62d0d5e71fed0cb96891da93a0f344c
6
+ metadata.gz: 917915fc72c29b668716d3234f2f85e8c92406ea14a63e82284750a5536ec016acb8714064888732eed9fb1443cb803c11e0764b23a76de9de64a9fda11d577f
7
+ data.tar.gz: f30214be433882a3be04fb988fcd1d4860c50c8cb8beced94f8b7529f45904c8a8c1eb12486e39f890ccce39f1321a02f1e92fce2cc07ca24f1a86509ddd4a59
@@ -1,3 +1,41 @@
1
+ ## 0.8.1 (2021-01-04)
2
+
3
+ * Fix blank email body when `json: true` and `ActionController::API` descendant are used (@janko)
4
+
5
+ * Make view and email rendering work when there are multiple configurations and one is `json: :only` (@janko)
6
+
7
+ * Don't attempt to protect against forgery when `ActionController::API` descendant is used (@janko)
8
+
9
+ * Mark content of rodauth built-in partials as HTML-safe (@janko)
10
+
11
+ ## 0.8.0 (2021-01-03)
12
+
13
+ * Add `--api` option to `rodauth:install` generator for choosing JSON-only configuration (@janko)
14
+
15
+ * Don't blow up when a Rodauth request is made using an unsupported HTTP verb (@janko)
16
+
17
+ ## 0.7.0 (2020-11-27)
18
+
19
+ * Add `#rails_controller_eval` method for running code in context of a controller instance (@janko)
20
+
21
+ * Detect `secret_key_base` from credentials and `$SECRET_KEY_BASE` environment variable (@janko)
22
+
23
+ ## 0.6.1 (2020-11-25)
24
+
25
+ * Generate the Rodauth controller for API-only Rails apps as well (@janko)
26
+
27
+ * Fix remember cookie deadline not extending in remember feature (@janko)
28
+
29
+ ## 0.6.0 (2020-11-22)
30
+
31
+ * Add `Rodauth::Rails.rodauth` method for retrieving Rodauth instance outside of request context (@janko)
32
+
33
+ * Add default Action Dispatch response headers in Rodauth responses (@janko)
34
+
35
+ * Run controller rescue handlers around Rodauth actions (@janko)
36
+
37
+ * Run controller action callbacks around Rodauth actions (@janko)
38
+
1
39
  ## 0.5.0 (2020-11-16)
2
40
 
3
41
  * Support more Active Record adapters in `rodauth:install` generator (@janko)
data/README.md CHANGED
@@ -4,16 +4,57 @@ 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 with Rodauth](https://janko.io/adding-authentication-in-rails-with-rodauth/)
16
+ * [Adding Multifactor Authentication in Rails with Rodauth](https://janko.io/adding-multifactor-authentication-in-rails-with-rodauth/)
17
+
18
+ ## Why Rodauth?
19
+
20
+ There are already several popular authentication solutions for Rails (Devise,
21
+ Sorcery, Clearance, Authlogic), so why would you choose Rodauth? Well, because
22
+ it has many advantages over the mentioned alternatives:
23
+
24
+ * multifactor authentication ([TOTP][otp], [SMS codes][sms_codes], [recovery codes][recovery_codes], [WebAuthn][webauthn])
25
+ * standardized [JSON API support][jwt] (for every feature)
26
+ * enterprise security features ([password complexity][password_complexity], [disallow password reuse][disallow_password_reuse], [password expiration][password_expiration], [session expiration][session_expiration], [single session][single_session], [account expiration][account_expiration])
27
+ * [email authentication][email_auth] (aka "passwordless")
28
+ * [audit logging][audit_logging] (for any action)
29
+ * ability to protect password hashes even in case of SQL injection ([more details][password protection])
30
+ * additional bruteforce protection for tokens ([more details][bruteforce tokens])
31
+ * uniform configuration DSL (any setting can be static or dynamic)
32
+ * consistent before/after hooks around everything
33
+ * dedicated object encapsulating all authentication logic
34
+
35
+ ## Upgrading
36
+
37
+ ### Upgrading to 0.7.0
38
+
39
+ Starting from version 0.7.0, rodauth-rails now correctly detects Rails
40
+ application's `secret_key_base` when setting default `hmac_secret`, including
41
+ when it's set via credentials or `$SECRET_KEY_BASE` environment variable. This
42
+ means that your authentication will now be more secure by default, and Rodauth
43
+ features that require `hmac_secret` should now work automatically as well.
44
+
45
+ However, if you've already been using rodauth-rails in production, where the
46
+ `secret_key_base` is set via credentials or environment variable and `hmac_secret`
47
+ was not explicitly set, the fact that your authentication will now start using
48
+ HMACs has backwards compatibility considerations. See the [Rodauth
49
+ documentation][hmac] for instructions on how to safely transition, or just set
50
+ `hmac_secret nil` in your Rodauth configuration.
51
+
11
52
  ## Installation
12
53
 
13
54
  Add the gem to your Gemfile:
14
55
 
15
56
  ```rb
16
- gem "rodauth-rails", "~> 0.4"
57
+ gem "rodauth-rails", "~> 0.6"
17
58
 
18
59
  # gem "jwt", require: false # for JWT feature
19
60
  # gem "rotp", require: false # for OTP feature
@@ -25,10 +66,17 @@ Then run `bundle install`.
25
66
 
26
67
  Next, run the install generator:
27
68
 
28
- ```
69
+ ```sh
29
70
  $ rails generate rodauth:install
30
71
  ```
31
72
 
73
+ Or if you want Rodauth endpoints to be exposed via JSON API:
74
+
75
+ ```sh
76
+ $ rails generate rodauth:install --api
77
+ $ bundle add jwt
78
+ ```
79
+
32
80
  The generator will create the following files:
33
81
 
34
82
  * Rodauth migration at `db/migrate/*_create_rodauth.rb`
@@ -111,8 +159,9 @@ end
111
159
 
112
160
  ### Controller
113
161
 
114
- Your Rodauth app will by default use `RodauthController` for view rendering
115
- and CSRF protection.
162
+ Your Rodauth app will by default use `RodauthController` for view rendering,
163
+ CSRF protection, and running controller callbacks and rescue handlers around
164
+ Rodauth actions.
116
165
 
117
166
  ```rb
118
167
  # app/controllers/rodauth_controller.rb
@@ -131,9 +180,11 @@ class Account < ApplicationRecord
131
180
  end
132
181
  ```
133
182
 
134
- ## Getting started
183
+ ## Usage
184
+
185
+ ### Routes
135
186
 
136
- First, let's see what routes our Rodauth middleware will handle:
187
+ We can see the list of routes our Rodauth middleware handles:
137
188
 
138
189
  ```sh
139
190
  $ rails rodauth:routes
@@ -155,54 +206,57 @@ Routes handled by RodauthApp:
155
206
  /close-account rodauth.close_account_path
156
207
  ```
157
208
 
158
- We can use this information to add some basic authentication navigation links
159
- to our home page:
209
+ Using this information, we could add some basic authentication links to our
210
+ navigation header:
160
211
 
161
212
  ```erb
162
- <ul>
163
- <% if rodauth.authenticated? %>
164
- <li><%= link_to "Sign out", rodauth.logout_path, method: :post %></li>
165
- <% else %>
166
- <li><%= link_to "Sign in", rodauth.login_path %></li>
167
- <li><%= link_to "Sign up", rodauth.create_account_path %></li>
168
- <% end %>
169
- </ul>
213
+ <% if rodauth.logged_in? %>
214
+ <%= link_to "Sign out", rodauth.logout_path, method: :post %>
215
+ <% else %>
216
+ <%= link_to "Sign in", rodauth.login_path %>
217
+ <%= link_to "Sign up", rodauth.create_account_path %>
218
+ <% end %>
170
219
  ```
171
220
 
172
- These links are fully functional, feel free to visit them and interact with the
221
+ These routes are fully functional, feel free to visit them and interact with the
173
222
  pages. The templates that ship with Rodauth aim to provide a complete
174
223
  authentication experience, and the forms use [Bootstrap] markup.
175
224
 
176
- Let's also load the account record for authenticated requests and expose it via
177
- `#current_account`:
225
+ ### Current account
226
+
227
+ To be able to fetch currently authenticated account, let's define a
228
+ `#current_account` method that fetches the account id from session and
229
+ retrieves the corresponding account record:
178
230
 
179
231
  ```rb
180
232
  # app/controllers/application_controller.rb
181
233
  class ApplicationController < ActionController::Base
182
- before_action :load_account, if: -> { rodauth.authenticated? }
234
+ before_action :current_account, if: -> { rodauth.logged_in? }
183
235
 
184
236
  private
185
237
 
186
- def load_account
187
- @current_account = Account.find(rodauth.session_value)
238
+ def current_account
239
+ @current_account ||= Account.find(rodauth.session_value)
188
240
  rescue ActiveRecord::RecordNotFound
189
241
  rodauth.logout
190
242
  rodauth.login_required
191
243
  end
192
-
193
- attr_reader :current_account
194
244
  helper_method :current_account
195
245
  end
196
246
  ```
247
+
248
+ This allows us to access the current account in controllers and views:
249
+
197
250
  ```erb
198
251
  <p>Authenticated as: <%= current_account.email %></p>
199
252
  ```
200
253
 
201
254
  ### Requiring authentication
202
255
 
203
- Next, we'll likely want to require authentication for certain sections/pages of
204
- our app. We can do this in our Rodauth app's routing block, which helps keep
205
- the authentication logic encapsulated:
256
+ We'll likely want to require authentication for certain parts of our app,
257
+ redirecting the user to the login page if they're not logged in. We can do this
258
+ in our Rodauth app's routing block, which helps keep the authentication logic
259
+ encapsulated:
206
260
 
207
261
  ```rb
208
262
  # app/lib/rodauth_app.rb
@@ -260,9 +314,9 @@ end
260
314
 
261
315
  ### Views
262
316
 
263
- The templates built into Rodauth are useful when getting started, but at some
264
- point we'll probably want more control over the markup. For that we can run the
265
- following command:
317
+ The templates built into Rodauth are useful when getting started, but soon
318
+ you'll want to start editing the markup. You can run the following command to
319
+ copy Rodauth templates into your Rails app:
266
320
 
267
321
  ```sh
268
322
  $ rails generate rodauth:views
@@ -286,7 +340,7 @@ $ rails generate rodauth:views --all
286
340
  ```
287
341
 
288
342
  You can also tell the generator to create views into another directory (in this
289
- case make sure to rename the Rodauth controller accordingly).
343
+ case make sure to rename the Rodauth controller accordingly):
290
344
 
291
345
  ```sh
292
346
  # generates views into app/views/authentication
@@ -351,7 +405,7 @@ $ rails generate rodauth:mailer
351
405
  ```
352
406
 
353
407
  This will create a `RodauthMailer` with the associated mailer views in
354
- `app/views/rodauth_mailer` directory.
408
+ `app/views/rodauth_mailer` directory:
355
409
 
356
410
  ```rb
357
411
  # app/mailers/rodauth_mailer.rb
@@ -366,8 +420,8 @@ end
366
420
  ```
367
421
 
368
422
  You can then uncomment the lines in your Rodauth configuration to have it call
369
- your mailer. If you've enabled additional authentication features, make sure to
370
- override their `send_*_email` methods as well.
423
+ your mailer. If you've enabled additional authentication features that send
424
+ emails, make sure to override their `create_*_email` methods as well.
371
425
 
372
426
  ```rb
373
427
  # app/lib/rodauth_app.rb
@@ -375,43 +429,45 @@ class RodauthApp < Rodauth::Rails::App
375
429
  # ...
376
430
  configure do
377
431
  # ...
378
- send_reset_password_email do
379
- mailer_send(:reset_password, email_to, reset_password_email_link)
432
+ create_reset_password_email do
433
+ RodauthMailer.reset_password(email_to, reset_password_email_link)
380
434
  end
381
- send_verify_account_email do
382
- mailer_send(:verify_account, email_to, verify_account_email_link)
435
+ create_verify_account_email do
436
+ RodauthMailer.verify_account(email_to, verify_account_email_link)
383
437
  end
384
- send_verify_login_change_email do |login|
385
- mailer_send(:verify_login_change, login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
438
+ create_verify_login_change_email do |login|
439
+ RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
386
440
  end
387
- send_password_changed_email do
388
- mailer_send(:password_changed, email_to)
441
+ create_password_changed_email do
442
+ RodauthMailer.password_changed(email_to)
389
443
  end
390
- # send_email_auth_email do
391
- # mailer_send(:email_auth, email_to, email_auth_email_link)
444
+ # create_email_auth_email do
445
+ # RodauthMailer.email_auth(email_to, email_auth_email_link)
392
446
  # end
393
- # send_unlock_account_email do
394
- # mailer_send(:unlock_account, email_to, unlock_account_email_link)
447
+ # create_unlock_account_email do
448
+ # RodauthMailer.unlock_account(email_to, unlock_account_email_link)
395
449
  # end
396
- auth_class_eval do
450
+ send_email do |email|
397
451
  # queue email delivery on the mailer after the transaction commits
398
- def mailer_send(type, *args)
399
- db.after_commit do
400
- RodauthMailer.public_send(type, *args).deliver_later
401
- end
402
- end
452
+ db.after_commit { email.deliver_later }
403
453
  end
404
454
  # ...
405
455
  end
406
456
  end
407
457
  ```
408
458
 
459
+ This approach can be used even if you're using a 3rd-party service for
460
+ transactional emails, where emails are sent via HTTP instead of SMTP. Whatever
461
+ the `create_*_email` block returns will be passed to `send_email`, so you can
462
+ be creative.
463
+
409
464
  ### Migrations
410
465
 
411
- The install generator will have created some default tables, but you can use
412
- the migration generator to create tables for any additional Rodauth features:
466
+ The install generator will create a migration for tables used by the Rodauth
467
+ features enabled by default. For any additional features, you can use the
468
+ migration generator to create the corresponding tables:
413
469
 
414
- ```
470
+ ```sh
415
471
  $ rails generate rodauth:migration otp sms_codes recovery_codes
416
472
  ```
417
473
  ```rb
@@ -425,36 +481,50 @@ class CreateRodauthOtpSmsCodesRecoveryCodes < ActiveRecord::Migration
425
481
  end
426
482
  ```
427
483
 
428
- ### JSON API
484
+ ### Calling controller methods
429
485
 
430
- JSON API support in Rodauth is provided by the [JWT feature]. First you'll need
431
- to add the [JWT gem] to your Gemfile:
486
+ When using Rodauth before/after hooks or generally overriding your Rodauth
487
+ configuration, in some cases you might want to call methods defined on your
488
+ controllers. You can do so with `rails_controller_eval`, for example:
432
489
 
433
490
  ```rb
434
- gem "jwt"
491
+ # app/controllers/application_controller.rb
492
+ class ApplicationController < ActionController::Base
493
+ private
494
+ def setup_tracking(account_id)
495
+ # ... some implementation ...
496
+ end
497
+ end
435
498
  ```
436
-
437
- The following configuration will enable the Rodauth endpoints to be accessed
438
- via JSON requests (in addition to HTML requests):
439
-
440
499
  ```rb
441
500
  # app/lib/rodauth_app.rb
442
501
  class RodauthApp < Rodauth::Rails::App
443
- configure(json: true) do
444
- # ...
445
- enable :jwt
446
- jwt_secret "...your secret key..."
447
- # ...
502
+ configure do
503
+ after_create_account do
504
+ rails_controller_eval { setup_tracking(account_id) }
505
+ end
448
506
  end
449
507
  end
450
508
  ```
451
509
 
452
- If you want the endpoints to be only accessible via JSON requests, or if your
453
- Rails app is in API-only mode, instead of `json: true` pass `json: :only` to
454
- the configure method.
510
+ ### Rodauth instance
511
+
512
+ In some cases you might need to use Rodauth more programmatically, and perform
513
+ Rodauth operations outside of the request context. rodauth-rails gives you the
514
+ ability to retrieve the Rodauth instance:
455
515
 
456
- Make sure to store the `jwt_secret` in a secure place, such as Rails
457
- credentials or environment variables.
516
+ ```rb
517
+ rodauth = Rodauth::Rails.rodauth # or Rodauth::Rails.rodauth(:secondary)
518
+
519
+ rodauth.login_url #=> "https://example.com/login"
520
+ rodauth.account_from_login("user@example.com") # loads user by email
521
+ rodauth.password_match?("secret") #=> true
522
+ rodauth.setup_account_verification
523
+ rodauth.close_account
524
+ ```
525
+
526
+ This Rodauth instance will be initialized with basic Rack env that allows is it
527
+ to generate URLs, using `config.action_mailer.default_url_options` options.
458
528
 
459
529
  ## How it works
460
530
 
@@ -500,19 +570,45 @@ end
500
570
  The `Rodauth::Rails::App` class is a [Roda] subclass that provides Rails
501
571
  integration for Rodauth:
502
572
 
503
- * uses Rails' flash instead of Roda's
504
- * uses Rails' CSRF protection instead of Roda's
573
+ * uses Action Dispatch flash instead of Roda's
574
+ * uses Action Dispatch CSRF protection instead of Roda's
505
575
  * sets [HMAC] secret to Rails' secret key base
506
- * uses ActionController for rendering templates
507
- * uses ActionMailer for sending emails
576
+ * uses Action Controller for rendering templates
577
+ * runs Action Controller callbacks & rescue handlers around Rodauth actions
578
+ * uses Action Mailer for sending emails
508
579
 
509
- The `configure { ... }` method wraps configuring the Rodauth plugin, forwarding
580
+ The `configure` method wraps configuring the Rodauth plugin, forwarding
510
581
  any additional [plugin options].
511
582
 
512
583
  ```rb
513
- configure { ... } # defining default Rodauth configuration
514
- configure(json: true) { ... } # passing options to the Rodauth plugin
515
- configure(:secondary) { ... } # defining multiple Rodauth configurations
584
+ class RodauthApp < Rodauth::Rails::App
585
+ configure { ... } # defining default Rodauth configuration
586
+ configure(json: true) { ... } # passing options to the Rodauth plugin
587
+ configure(:secondary) { ... } # defining multiple Rodauth configurations
588
+ end
589
+ ```
590
+
591
+ The `route` block is provided by Roda, and it's called on each request before
592
+ it reaches the Rails router.
593
+
594
+ ```rb
595
+ class RodauthApp < Rodauth::Rails::App
596
+ route do |r|
597
+ # ... called before each request ...
598
+ end
599
+ end
600
+ ```
601
+
602
+ Since `Rodauth::Rails::App` is just a Roda subclass, you can do anything you
603
+ would with a Roda app, such as loading additional Roda plugins:
604
+
605
+ ```rb
606
+ class RodauthApp < Rodauth::Rails::App
607
+ plugin :request_headers # easier access to request headers
608
+ plugin :typecast_params # methods for conversion of request params
609
+ plugin :default_headers, { "Foo" => "Bar" }
610
+ # ...
611
+ end
516
612
  ```
517
613
 
518
614
  ### Sequel
@@ -528,6 +624,142 @@ connection (using the [sequel-activerecord_connection] gem).
528
624
  This means that, from the usage perspective, Sequel can be considered just
529
625
  as an implementation detail of Rodauth.
530
626
 
627
+ ## JSON API
628
+
629
+ JSON API support in Rodauth is provided by the [JWT feature][jwt]. You'll need
630
+ to install the [JWT gem], enable JSON support and enable the JWT feature:
631
+
632
+ ```sh
633
+ $ bundle add jwt
634
+ ```
635
+ ```rb
636
+ # app/lib/rodauth_app.rb
637
+ class RodauthApp < Rodauth::Rails::App
638
+ configure(json: :only) do
639
+ # ...
640
+ enable :jwt
641
+ # make sure to store the JWT secret below in a safe place
642
+ jwt_secret "...your secret key..."
643
+ # ...
644
+ end
645
+ end
646
+ ```
647
+
648
+ With the above configuration, Rodauth routes will only be accessible via JSON
649
+ requests. If you still want to allow HTML access alongside JSON, change `json:
650
+ :only` to `json: true`.
651
+
652
+ Emails will automatically work in JSON-only mode, because `Rodauth::Rails::App`
653
+ comes with Roda's `render` plugin loaded. They are customized the same as in
654
+ the non-JSON case.
655
+
656
+ ## OmniAuth
657
+
658
+ While Rodauth doesn't yet come with [OmniAuth] integration, we can build one
659
+ ourselves using the existing Rodauth API.
660
+
661
+ In order to allow the user to login via multiple external providers, let's
662
+ create an `account_identities` table that will have a many-to-one relationship
663
+ with the `accounts` table:
664
+
665
+ ```sh
666
+ $ rails generate model AccountIdentity
667
+ ```
668
+ ```rb
669
+ # db/migrate/*_create_account_identities.rb
670
+ class CreateAccountIdentities < ActiveRecord::Migration
671
+ def change
672
+ create_table :account_identities do |t|
673
+ t.references :account, null: false, foreign_key: { on_delete: :cascade }
674
+ t.string :provider, null: false
675
+ t.string :uid, null: false
676
+ t.jsonb :info, null: false, default: {} # adjust JSON column type for your database
677
+
678
+ t.timestamps
679
+
680
+ t.index [:provider, :uid], unique: true
681
+ end
682
+ end
683
+ end
684
+ ```
685
+ ```rb
686
+ # app/models/account_identity.rb
687
+ class AcccountIdentity < ApplicationRecord
688
+ belongs_to :account
689
+ end
690
+ ```
691
+ ```rb
692
+ # app/models/account.rb
693
+ class Account < ApplicationRecord
694
+ has_many :identities, class_name: "AccountIdentity"
695
+ end
696
+ ```
697
+
698
+ Let's assume we want to implement Facebook login, and have added the
699
+ corresponding OmniAuth strategy to the middleware stack, together with an
700
+ authorization link on the login form:
701
+
702
+ ```rb
703
+ Rails.application.config.middleware.use OmniAuth::Builder do
704
+ provider :facebook, ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_APP_SECRET"],
705
+ scope: "email", callback_path: "/auth/facebook/callback"
706
+ end
707
+ ```
708
+ ```erb
709
+ <%= link_to "Login via Facebook", "/auth/facebook" %>
710
+ ```
711
+
712
+ Let's implement the OmniAuth callback endpoint on our Rodauth controller:
713
+
714
+ ```rb
715
+ # config/routes.rb
716
+ Rails.application.routes.draw do
717
+ # ...
718
+ get "/auth/:provider/callback", to: "rodauth#omniauth"
719
+ end
720
+ ```
721
+ ```rb
722
+ # app/controllres/rodauth_controller.rb
723
+ class RodauthController < ApplicationController
724
+ def omniauth
725
+ auth = request.env["omniauth.auth"]
726
+
727
+ # attempt to find existing identity directly
728
+ identity = AccountIdentity.find_by(provider: auth["provider"], uid: auth["uid"])
729
+
730
+ if identity
731
+ # update any external info changes
732
+ identity.update!(info: auth["info"])
733
+ # set account from identity
734
+ account = identity.account
735
+ end
736
+
737
+ # attempt to find an existing account by email
738
+ account ||= Account.find_by(email: auth["info"]["email"])
739
+
740
+ # disallow login if account is not verified
741
+ if account && account.status != rodauth.account_open_status_value
742
+ redirect_to rodauth.login_path, alert: rodauth.unverified_account_message
743
+ return
744
+ end
745
+
746
+ # create new account if it doesn't exist
747
+ unless account
748
+ account = Account.create!(email: auth["info"]["email"])
749
+ end
750
+
751
+ # create new identity if it doesn't exist
752
+ unless identity
753
+ account.identities.create!(provider: auth["provider"], uid: auth["uid"], info: auth["info"])
754
+ end
755
+
756
+ # login with Rodauth
757
+ rodauth.account_from_login(account.email)
758
+ rodauth.login("omniauth")
759
+ end
760
+ end
761
+ ```
762
+
531
763
  ## Configuring
532
764
 
533
765
  For the list of configuration methods provided by Rodauth, see the [feature
@@ -561,6 +793,37 @@ Rodauth::Rails.configure do |config|
561
793
  end
562
794
  ```
563
795
 
796
+ ## Custom extensions
797
+
798
+ When developing custom extensions for Rodauth inside your Rails project, it's
799
+ better to use plain modules (at least in the beginning), because Rodauth
800
+ feature API doesn't yet support Zeitwerk reloading well.
801
+
802
+ ```rb
803
+ # app/lib/rodauth_argon2.rb
804
+ module RodauthArgon2
805
+ def password_hash(password)
806
+ Argon2::Password.create(password, t_cost: password_hash_cost, m_cost: password_hash_cost)
807
+ end
808
+
809
+ def password_hash_match?(hash, password)
810
+ Argon2::Password.verify_password(password, hash)
811
+ end
812
+ end
813
+ ```
814
+ ```rb
815
+ # app/lib/rodauth_app.rb
816
+ class RodauthApp < Rodauth::Rails::App
817
+ configure do
818
+ # ...
819
+ auth_class_eval do
820
+ include RodauthArgon2
821
+ end
822
+ # ...
823
+ end
824
+ end
825
+ ```
826
+
564
827
  ## Testing
565
828
 
566
829
  If you're writing system tests, it's generally better to go through the actual
@@ -633,17 +896,15 @@ Rodauth method for creating database functions:
633
896
 
634
897
  ```rb
635
898
  # db/migrate/*_create_rodauth_database_functions.rb
899
+ require "rodauth/migrations"
900
+
636
901
  class CreateRodauthDatabaseFunctions < ActiveRecord::Migration
637
902
  def up
638
- # ...
639
903
  Rodauth.create_database_authentication_functions(DB)
640
- # ...
641
904
  end
642
905
 
643
906
  def down
644
- # ...
645
907
  Rodauth.drop_database_authentication_functions(DB)
646
- # ...
647
908
  end
648
909
  end
649
910
  ```
@@ -700,9 +961,7 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
700
961
 
701
962
  [Rodauth]: https://github.com/jeremyevans/rodauth
702
963
  [Sequel]: https://github.com/jeremyevans/sequel
703
- [rendering views outside of controllers]: https://blog.bigbinary.com/2016/01/08/rendering-views-outside-of-controllers-in-rails-5.html
704
964
  [feature documentation]: http://rodauth.jeremyevans.net/documentation.html
705
- [JWT feature]: http://rodauth.jeremyevans.net/rdoc/files/doc/jwt_rdoc.html
706
965
  [JWT gem]: https://github.com/jwt/ruby-jwt
707
966
  [Bootstrap]: https://getbootstrap.com/
708
967
  [Roda]: http://roda.jeremyevans.net/
@@ -711,3 +970,20 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
711
970
  [Rodauth migration]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Creating+tables
712
971
  [sequel-activerecord_connection]: https://github.com/janko/sequel-activerecord_connection
713
972
  [plugin options]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Plugin+Options
973
+ [hmac]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC
974
+ [OmniAuth]: https://github.com/omniauth/omniauth
975
+ [otp]: http://rodauth.jeremyevans.net/rdoc/files/doc/otp_rdoc.html
976
+ [sms_codes]: http://rodauth.jeremyevans.net/rdoc/files/doc/sms_codes_rdoc.html
977
+ [recovery_codes]: http://rodauth.jeremyevans.net/rdoc/files/doc/recovery_codes_rdoc.html
978
+ [webauthn]: http://rodauth.jeremyevans.net/rdoc/files/doc/webauthn_rdoc.html
979
+ [jwt]: http://rodauth.jeremyevans.net/rdoc/files/doc/jwt_rdoc.html
980
+ [email_auth]: http://rodauth.jeremyevans.net/rdoc/files/doc/email_auth_rdoc.html
981
+ [audit_logging]: http://rodauth.jeremyevans.net/rdoc/files/doc/audit_logging_rdoc.html
982
+ [password protection]: https://github.com/jeremyevans/rodauth#label-Password+Hash+Access+Via+Database+Functions
983
+ [bruteforce tokens]: https://github.com/jeremyevans/rodauth#label-Tokens
984
+ [password_complexity]: http://rodauth.jeremyevans.net/rdoc/files/doc/password_complexity_rdoc.html
985
+ [disallow_password_reuse]: http://rodauth.jeremyevans.net/rdoc/files/doc/disallow_password_reuse_rdoc.html
986
+ [password_expiration]: http://rodauth.jeremyevans.net/rdoc/files/doc/password_expiration_rdoc.html
987
+ [session_expiration]: http://rodauth.jeremyevans.net/rdoc/files/doc/session_expiration_rdoc.html
988
+ [single_session]: http://rodauth.jeremyevans.net/rdoc/files/doc/single_session_rdoc.html
989
+ [account_expiration]: http://rodauth.jeremyevans.net/rdoc/files/doc/account_expiration_rdoc.html
@@ -13,6 +13,15 @@ module Rodauth
13
13
  source_root "#{__dir__}/templates"
14
14
  namespace "rodauth:install"
15
15
 
16
+ # The :api option is a Rails-recognized option that always
17
+ # defaults to false, so we make it use our provided default
18
+ # value instead.
19
+ def self.default_value_for_option(name, options)
20
+ name == :api ? options[:default] : super
21
+ end
22
+
23
+ class_option :api, type: :boolean, desc: "Generate JSON-only configuration"
24
+
16
25
  def create_rodauth_migration
17
26
  return unless defined?(ActiveRecord::Base)
18
27
 
@@ -35,8 +44,6 @@ module Rodauth
35
44
  end
36
45
 
37
46
  def create_rodauth_controller
38
- return if api_only?
39
-
40
47
  template "app/controllers/rodauth_controller.rb"
41
48
  end
42
49
 
@@ -77,9 +84,11 @@ module Rodauth
77
84
  end
78
85
 
79
86
  def api_only?
80
- return unless ::Rails.gem_version >= Gem::Version.new("5.0")
81
-
82
- ::Rails.application.config.api_only
87
+ if options.key?(:api)
88
+ options[:api]
89
+ elsif ::Rails.gem_version >= Gem::Version.new("5.0")
90
+ ::Rails.application.config.api_only
91
+ end
83
92
  end
84
93
 
85
94
  def migration_features
@@ -1,3 +1,4 @@
1
1
  class RodauthController < ApplicationController
2
- # used by Rodauth for rendering views and CSRF protection
2
+ # used by Rodauth for rendering views, CSRF protection, and running any
3
+ # registered action callbacks and rescue_from handlers
3
4
  end
@@ -15,11 +15,9 @@ class RodauthApp < Rodauth::Rails::App
15
15
  # Defaults to Rails `secret_key_base`, but you can use your own secret key.
16
16
  # hmac_secret "<%= SecureRandom.hex(64) %>"
17
17
 
18
- <% unless api_only? -%>
19
18
  # Specify the controller used for view rendering and CSRF verification.
20
19
  rails_controller { RodauthController }
21
20
 
22
- <% end -%>
23
21
  # Store account status in a text column.
24
22
  account_status_column :status
25
23
  account_unverified_status_value "unverified"
@@ -59,31 +57,27 @@ class RodauthApp < Rodauth::Rails::App
59
57
 
60
58
  # ==> Emails
61
59
  # Uncomment the lines below once you've imported mailer views.
62
- # send_reset_password_email do
63
- # mailer_send(:reset_password, email_to, reset_password_email_link)
60
+ # create_reset_password_email do
61
+ # RodauthMailer.reset_password(email_to, reset_password_email_link)
64
62
  # end
65
- # send_verify_account_email do
66
- # mailer_send(:verify_account, email_to, verify_account_email_link)
63
+ # create_verify_account_email do
64
+ # RodauthMailer.verify_account(email_to, verify_account_email_link)
67
65
  # end
68
- # send_verify_login_change_email do |login|
69
- # mailer_send(:verify_login_change, login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
66
+ # create_verify_login_change_email do |login|
67
+ # RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
70
68
  # end
71
- # send_password_changed_email do
72
- # mailer_send(:password_changed, email_to)
69
+ # create_password_changed_email do
70
+ # RodauthMailer.password_changed(email_to)
73
71
  # end
74
- # # send_email_auth_email do
75
- # # mailer_send(:email_auth, email_to, email_auth_email_link)
72
+ # # create_email_auth_email do
73
+ # # RodauthMailer.email_auth(email_to, email_auth_email_link)
76
74
  # # end
77
- # # send_unlock_account_email do
78
- # # mailer_send(:unlock_account, email_to, unlock_account_email_link)
75
+ # # create_unlock_account_email do
76
+ # # RodauthMailer.unlock_account(email_to, unlock_account_email_link)
79
77
  # # end
80
- # auth_class_eval do
78
+ # send_email do |email|
81
79
  # # queue email delivery on the mailer after the transaction commits
82
- # def mailer_send(type, *args)
83
- # db.after_commit do
84
- # RodauthMailer.public_send(type, *args).deliver_later
85
- # end
86
- # end
80
+ # db.after_commit { email.deliver_later }
87
81
  # end
88
82
 
89
83
  # In the meantime you can tweak settings for emails created by Rodauth
@@ -9,14 +9,43 @@ module Rodauth
9
9
  # This allows the developer to avoid loading Rodauth at boot time.
10
10
  autoload :App, "rodauth/rails/app"
11
11
 
12
- def self.configure
13
- yield self
14
- end
15
-
16
12
  @app = nil
17
13
  @middleware = true
18
14
 
19
15
  class << self
16
+ def rodauth(name = nil)
17
+ url_options = ActionMailer::Base.default_url_options
18
+
19
+ scheme = url_options[:protocol] || "http"
20
+ port = url_options[:port]
21
+ port ||= Rack::Request::DEFAULT_PORTS[scheme] if Gem::Version.new(Rack.release) < Gem::Version.new("2.0")
22
+ host = url_options[:host]
23
+ host += ":#{port}" if port
24
+
25
+ rack_env = {
26
+ "HTTP_HOST" => host,
27
+ "rack.url_scheme" => scheme,
28
+ }
29
+
30
+ scope = app.new(rack_env)
31
+
32
+ scope.rodauth(name)
33
+ end
34
+
35
+ if ::Rails.gem_version >= Gem::Version.new("5.2")
36
+ def secret_key_base
37
+ ::Rails.application.secret_key_base
38
+ end
39
+ else
40
+ def secret_key_base
41
+ ::Rails.application.secrets.secret_key_base
42
+ end
43
+ end
44
+
45
+ def configure
46
+ yield self
47
+ end
48
+
20
49
  attr_writer :app
21
50
  attr_writer :middleware
22
51
 
@@ -1,10 +1,14 @@
1
1
  require "roda"
2
+ require "rodauth"
3
+ require "rodauth/rails/feature"
2
4
 
3
5
  module Rodauth
4
6
  module Rails
5
7
  # The superclass for creating a Rodauth middleware.
6
8
  class App < Roda
7
- plugin :middleware
9
+ require "rodauth/rails/app/middleware"
10
+ plugin Middleware
11
+
8
12
  plugin :hooks
9
13
  plugin :render, layout: false
10
14
 
@@ -18,6 +22,12 @@ module Rodauth
18
22
  # load the Rails integration
19
23
  enable :rails
20
24
 
25
+ if options[:json] == :only && ActionPack.version >= Gem::Version.new("5.0")
26
+ rails_controller { ActionController::API }
27
+ else
28
+ rails_controller { ActionController::Base }
29
+ end
30
+
21
31
  # database functions are more complex to set up, so disable them by default
22
32
  use_database_authentication_functions? false
23
33
 
@@ -25,7 +35,7 @@ module Rodauth
25
35
  set_deadline_values? true
26
36
 
27
37
  # use HMACs for additional security
28
- hmac_secret { ::Rails.application.secrets.secret_key_base }
38
+ hmac_secret { Rodauth::Rails.secret_key_base }
29
39
 
30
40
  # evaluate user configuration
31
41
  instance_exec(&block)
@@ -1,7 +1,7 @@
1
1
  module Rodauth
2
2
  module Rails
3
3
  class App
4
- # Sets up Rails' flash integration.
4
+ # Roda plugin that sets up Rails flash integration.
5
5
  module Flash
6
6
  def self.load_dependencies(app)
7
7
  app.plugin :hooks
@@ -0,0 +1,26 @@
1
+ module Rodauth
2
+ module Rails
3
+ class App
4
+ # Roda plugin that extends middleware plugin by propagating response headers.
5
+ module Middleware
6
+ def self.load_dependencies(app)
7
+ app.plugin :hooks
8
+ end
9
+
10
+ def self.configure(app)
11
+ app.after do
12
+ if response.empty? && response.headers.any?
13
+ env["rodauth.rails.headers"] = response.headers
14
+ end
15
+ end
16
+
17
+ app.plugin :middleware, handle_result: -> (env, res) do
18
+ if headers = env.delete("rodauth.rails.headers")
19
+ res[1] = headers.merge(res[1])
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -9,10 +9,11 @@ module Rodauth
9
9
  :rails_csrf_param,
10
10
  :rails_csrf_token,
11
11
  :rails_check_csrf!,
12
- :rails_controller_instance,
13
12
  :rails_controller,
14
13
  )
15
14
 
15
+ auth_cached_method :rails_controller_instance
16
+
16
17
  # Renders templates with layout. First tries to render a user-defined
17
18
  # template, otherwise falls back to Rodauth's template.
18
19
  def view(page, *)
@@ -25,7 +26,12 @@ module Rodauth
25
26
  def render(page)
26
27
  rails_render(partial: page.tr("-", "_"), layout: false) ||
27
28
  rails_render(action: page.tr("-", "_"), layout: false) ||
28
- super
29
+ super.html_safe
30
+ end
31
+
32
+ # Render Rails CSRF tags in Rodauth templates.
33
+ def csrf_tag(*)
34
+ rails_csrf_tag
29
35
  end
30
36
 
31
37
  # Verify Rails' authenticity token.
@@ -38,18 +44,77 @@ module Rodauth
38
44
  true
39
45
  end
40
46
 
41
- # Render Rails CSRF tags in Rodauth templates.
42
- def csrf_tag(*)
43
- rails_csrf_tag
44
- end
45
-
46
47
  # Default the flash error key to Rails' default :alert.
47
48
  def flash_error_key
48
49
  :alert
49
50
  end
50
51
 
52
+ # Evaluates the block in context of a Rodauth controller instance.
53
+ def rails_controller_eval(&block)
54
+ rails_controller_instance.instance_exec(&block)
55
+ end
56
+
57
+ def button(*)
58
+ super.html_safe
59
+ end
60
+
51
61
  private
52
62
 
63
+ # Runs controller callbacks and rescue handlers around Rodauth actions.
64
+ def _around_rodauth(&block)
65
+ result = nil
66
+
67
+ rails_controller_rescue do
68
+ rails_controller_callbacks do
69
+ result = catch(:halt) { super(&block) }
70
+ end
71
+ end
72
+
73
+ if rails_controller_instance.performed?
74
+ rails_controller_response
75
+ elsif result
76
+ result[1].merge!(rails_controller_instance.response.headers)
77
+ throw :halt, result
78
+ else
79
+ result
80
+ end
81
+ end
82
+
83
+ # Runs any #(before|around|after)_action controller callbacks.
84
+ def rails_controller_callbacks
85
+ # don't verify CSRF token as part of callbacks, Rodauth will do that
86
+ rails_controller_forgery_protection { false }
87
+
88
+ rails_controller_instance.run_callbacks(:process_action) do
89
+ # turn the setting back to default so that form tags generate CSRF tags
90
+ rails_controller_forgery_protection { rails_controller.allow_forgery_protection }
91
+
92
+ yield
93
+ end
94
+ end
95
+
96
+ # Runs any registered #rescue_from controller handlers.
97
+ def rails_controller_rescue
98
+ yield
99
+ rescue Exception => exception
100
+ rails_controller_instance.rescue_with_handler(exception) || raise
101
+
102
+ unless rails_controller_instance.performed?
103
+ raise Rodauth::Rails::Error, "rescue_from handler didn't write any response"
104
+ end
105
+ end
106
+
107
+ # Returns Roda response from controller response if set.
108
+ def rails_controller_response
109
+ controller_response = rails_controller_instance.response
110
+
111
+ response.status = controller_response.status
112
+ response.headers.merge! controller_response.headers
113
+ response.write controller_response.body
114
+
115
+ request.halt
116
+ end
117
+
53
118
  # Create emails with ActionMailer which uses configured delivery method.
54
119
  def create_email_to(to, subject, body)
55
120
  Mailer.create_email(to: to, from: email_from, subject: "#{email_subject_prefix}#{subject}", body: body)
@@ -62,13 +127,16 @@ module Rodauth
62
127
 
63
128
  # Calls the Rails renderer, returning nil if a template is missing.
64
129
  def rails_render(*args)
65
- return if only_json?
130
+ return if rails_api_controller?
66
131
 
67
- begin
68
- rails_controller_instance.render_to_string(*args)
69
- rescue ActionView::MissingTemplate
70
- nil
71
- end
132
+ rails_controller_instance.render_to_string(*args)
133
+ rescue ActionView::MissingTemplate
134
+ nil
135
+ end
136
+
137
+ # Calls the controller to verify the authenticity token.
138
+ def rails_check_csrf!
139
+ rails_controller_instance.send(:verify_authenticity_token)
72
140
  end
73
141
 
74
142
  # Hidden tag with Rails CSRF token inserted into Rodauth templates.
@@ -86,30 +154,37 @@ module Rodauth
86
154
  rails_controller_instance.send(:form_authenticity_token)
87
155
  end
88
156
 
89
- # Calls the controller to verify the authenticity token.
90
- def rails_check_csrf!
91
- rails_controller_instance.send(:verify_authenticity_token)
157
+ # allows/disables forgery protection
158
+ def rails_controller_forgery_protection(&value)
159
+ return if rails_api_controller?
160
+
161
+ rails_controller_instance.allow_forgery_protection = value.call
92
162
  end
93
163
 
94
164
  # Instances of the configured controller with current request's env hash.
95
- def rails_controller_instance
96
- request = ActionDispatch::Request.new(scope.env)
97
- instance = rails_controller.new
165
+ def _rails_controller_instance
166
+ controller = rails_controller.new
167
+ rails_request = ActionDispatch::Request.new(scope.env)
98
168
 
99
- if ActionPack.version >= Gem::Version.new("5.0")
100
- instance.set_request! request
101
- instance.set_response! rails_controller.make_response!(request)
102
- else
103
- instance.send(:set_response!, request)
104
- instance.instance_variable_set(:@_request, request)
105
- end
169
+ prepare_rails_controller(controller, rails_request)
170
+
171
+ controller
172
+ end
106
173
 
107
- instance
174
+ if ActionPack.version >= Gem::Version.new("5.0")
175
+ def prepare_rails_controller(controller, rails_request)
176
+ controller.set_request! rails_request
177
+ controller.set_response! rails_controller.make_response!(rails_request)
178
+ end
179
+ else
180
+ def prepare_rails_controller(controller, rails_request)
181
+ controller.send(:set_response!, rails_request)
182
+ controller.instance_variable_set(:@_request, rails_request)
183
+ end
108
184
  end
109
185
 
110
- # Controller class to use for rendering and CSRF protection.
111
- def rails_controller
112
- ActionController::Base
186
+ def rails_api_controller?
187
+ defined?(ActionController::API) && rails_controller <= ActionController::API
113
188
  end
114
189
 
115
190
  # ActionMailer subclass for correct email delivering.
@@ -3,19 +3,16 @@ namespace :rodauth do
3
3
  app = Rodauth::Rails.app
4
4
 
5
5
  puts "Routes handled by #{app}:"
6
- puts
7
6
 
8
- app.opts[:rodauths].each do |rodauth_name, rodauth_class|
9
- route_names = rodauth_class.routes
10
- .map { |handle_method| handle_method.to_s.sub(/\Ahandle_/, "") }
11
- .uniq
7
+ app.opts[:rodauths].each_key do |rodauth_name|
8
+ rodauth = Rodauth::Rails.rodauth(rodauth_name)
12
9
 
13
- rodauth = rodauth_class.allocate
10
+ routes = rodauth.class.routes.map do |handle_method|
11
+ path_method = "#{handle_method.to_s.sub(/\Ahandle_/, "")}_path"
14
12
 
15
- routes = route_names.map do |name|
16
13
  [
17
- rodauth.public_send(:"#{name}_path"),
18
- "rodauth#{rodauth_name && "(:#{rodauth_name})"}.#{name}_path",
14
+ rodauth.public_send(path_method),
15
+ "rodauth#{rodauth_name && "(:#{rodauth_name})"}.#{path_method}",
19
16
  ]
20
17
  end
21
18
 
@@ -25,8 +22,7 @@ namespace :rodauth do
25
22
  "#{path.ljust(padding)} #{code}"
26
23
  end
27
24
 
28
- puts " #{route_lines.join("\n ")}"
29
- puts
25
+ puts "\n #{route_lines.join("\n ")}" unless route_lines.empty?
30
26
  end
31
27
  end
32
28
  end
@@ -1,5 +1,5 @@
1
1
  module Rodauth
2
2
  module Rails
3
- VERSION = "0.5.0"
3
+ VERSION = "0.8.1"
4
4
  end
5
5
  end
@@ -17,8 +17,10 @@ Gem::Specification.new do |spec|
17
17
  spec.require_paths = ["lib"]
18
18
 
19
19
  spec.add_dependency "railties", ">= 4.2", "< 7"
20
- spec.add_dependency "rodauth", "~> 2.1"
20
+ spec.add_dependency "rodauth", "~> 2.7"
21
21
  spec.add_dependency "sequel-activerecord_connection", "~> 1.1"
22
22
  spec.add_dependency "tilt"
23
23
  spec.add_dependency "bcrypt"
24
+
25
+ spec.add_development_dependency "jwt"
24
26
  end
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: 0.5.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-16 00:00:00.000000000 Z
11
+ date: 2021-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '2.1'
39
+ version: '2.7'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '2.1'
46
+ version: '2.7'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sequel-activerecord_connection
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +86,20 @@ dependencies:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: jwt
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
89
103
  description: Provides Rails integration for Rodauth.
90
104
  email:
91
105
  - janko.marohnic@gmail.com
@@ -187,10 +201,10 @@ files:
187
201
  - lib/generators/rodauth/templates/db/migrate/create_rodauth.rb
188
202
  - lib/generators/rodauth/views_generator.rb
189
203
  - lib/rodauth-rails.rb
190
- - lib/rodauth/features/rails.rb
191
204
  - lib/rodauth/rails.rb
192
205
  - lib/rodauth/rails/app.rb
193
206
  - lib/rodauth/rails/app/flash.rb
207
+ - lib/rodauth/rails/app/middleware.rb
194
208
  - lib/rodauth/rails/controller_methods.rb
195
209
  - lib/rodauth/rails/feature.rb
196
210
  - lib/rodauth/rails/middleware.rb
@@ -1 +0,0 @@
1
- require "rodauth/rails/feature"