rails_authentication 0.3.0 → 0.5.0

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -14
  3. data/lib/generators/authentication/authentication_generator.rb +31 -0
  4. data/lib/generators/authentication/features/confirmable.rb +13 -12
  5. data/lib/generators/authentication/features/invitable.rb +14 -13
  6. data/lib/generators/authentication/features/lockable.rb +13 -12
  7. data/lib/generators/authentication/features/magic_link.rb +13 -12
  8. data/lib/generators/authentication/features/ott.rb +31 -0
  9. data/lib/generators/authentication/features/passkey.rb +36 -0
  10. data/lib/generators/authentication/features/recoverable.rb +13 -12
  11. data/lib/generators/authentication/features/registerable.rb +7 -6
  12. data/lib/generators/authentication/features/rememberable.rb +6 -5
  13. data/lib/generators/authentication/features/timeoutable.rb +7 -6
  14. data/lib/generators/authentication/features/trackable.rb +7 -6
  15. data/lib/generators/authentication/features/validatable.rb +5 -4
  16. data/lib/generators/authentication/templates/app/controllers/otts_controller.rb.tt +95 -0
  17. data/lib/generators/authentication/templates/app/controllers/passkey_sessions_controller.rb.tt +68 -0
  18. data/lib/generators/authentication/templates/app/controllers/sessions_controller.rb.tt +4 -0
  19. data/lib/generators/authentication/templates/app/controllers/webauthn_credentials_controller.rb.tt +43 -0
  20. data/lib/generators/authentication/templates/app/mailers/otts_mailer.rb.tt +6 -0
  21. data/lib/generators/authentication/templates/app/models/concerns/confirmable_concern.rb.tt +18 -17
  22. data/lib/generators/authentication/templates/app/models/concerns/ott_concern.rb.tt +50 -0
  23. data/lib/generators/authentication/templates/app/models/concerns/passkey_concern.rb.tt +19 -0
  24. data/lib/generators/authentication/templates/app/models/webauthn_credential.rb.tt +6 -0
  25. data/lib/generators/authentication/templates/app/views/otts/edit.html.erb.tt +79 -0
  26. data/lib/generators/authentication/templates/app/views/otts_mailer/ott.html.erb.tt +8 -0
  27. data/lib/generators/authentication/templates/app/views/otts_mailer/ott.text.erb.tt +6 -0
  28. data/lib/generators/authentication/templates/app/views/registrations/edit.html.erb.tt +4 -0
  29. data/lib/generators/authentication/templates/app/views/sessions/new.html.erb.tt +81 -0
  30. data/lib/generators/authentication/templates/app/views/webauthn_credentials/index.html.erb.tt +19 -0
  31. data/lib/generators/authentication/templates/app/views/webauthn_credentials/new.html.erb.tt +71 -0
  32. data/lib/generators/authentication/templates/config/initializers/webauthn.rb.tt +11 -0
  33. data/lib/generators/authentication/templates/db/migrate/add_ott_to_users.rb.tt +7 -0
  34. data/lib/generators/authentication/templates/db/migrate/add_webauthn_id_to_users.rb.tt +7 -0
  35. data/lib/generators/authentication/templates/db/migrate/create_webauthn_credentials.rb.tt +15 -0
  36. data/lib/rails_authentication/version.rb +1 -1
  37. metadata +19 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c71c1a30969abed6c581c67e3447c1968176e6e25c218894e64d5317472b873e
4
- data.tar.gz: 1f65cac490fae4c9f575d907bf70d4d059afdb1bcb5e8a56474b741b4eac4f3e
3
+ metadata.gz: 6369064c5074eb057abc1ed169b7efbe7ae0758730dc6c764b86fee19f96b0d3
4
+ data.tar.gz: 5bdc5cb01eb60fed2449f0a1544d29102c79f917faf345f86a1a86bca6b6adc6
5
5
  SHA512:
6
- metadata.gz: 5469da8db1ff529c5dd079b37a3499b1bc08b657560bdcd037607c407d6be292a306bcd146bcc99f30243435824a6fa9a58cb965a80edc0d7fb30435dcdc1cc3
7
- data.tar.gz: '0693170a1f4bdebe7ec41bfe6088ddbbc436225aa3a09b8d3216af9cf800bd36d461a9618fd022e0b45b1662c82382b13a0bf4cc10e715a9e7247fcd1d77fb18'
6
+ metadata.gz: da49badfb4b8c58c2525329479154961cb10cbd6b6d683a4dbc56171198e9ad1d1f31d097455f106d47d19332a14391ee0e4370394aa23535e85b47be6ebf0f8
7
+ data.tar.gz: 4407fbc0f0c7daafc4324fb1e0ba7c366c4c810fa81b579bf464fd2f2e31b7d5e3da6c6e8741b189e0399a28660b4e0a728d80b1bfec63282eee3f8c0d204756
data/README.md CHANGED
@@ -18,6 +18,8 @@ gem extends that same command to also install:
18
18
  | **Lockable** | Locks the account after 5 failed attempts; unlock via email or automatically after 1 hour |
19
19
  | **Invitable** | Invite users by email; blocks sign-in until they accept by choosing their own password |
20
20
  | **MagicLink** (opt-in) | Passwordless magic link sign-in via email — DB-backed, single-use, expiring tokens |
21
+ | **Ott** (opt-in) | Passwordless sign-in via an emailed 6-digit one-time code — replaces the password sign-in form |
22
+ | **Passkey** (opt-in) | WebAuthn passkey sign-in alongside the password form — usernameless, no email required |
21
23
 
22
24
  Everything is **generated into your app** as plain, readable code — controllers, views, mailers,
23
25
  migrations, and one model concern per feature. There is no runtime dependency on this gem: after
@@ -28,7 +30,7 @@ This gem is meant to be installed temporarily. Install it long enough to run the
28
30
  ## Installation
29
31
 
30
32
  Requires Rails >= 8.0 and, for the email-driven features (Confirmable, Recoverable, Lockable,
31
- Invitable, MagicLink), Action Mailer.
33
+ Invitable, MagicLink, Ott), Action Mailer.
32
34
 
33
35
  ```ruby
34
36
  # Gemfile
@@ -56,24 +58,46 @@ Available flags: `--skip-confirmable`, `--skip-recoverable`, `--skip-registerabl
56
58
  `--skip-lockable`, `--skip-invitable`, and `--reconfirmable` (Confirmable: postpone email address
57
59
  changes until the new address is confirmed, via an `unconfirmed_email` column).
58
60
 
59
- MagicLink is the one **opt-in** featureit changes the sign-in UX, so you have to ask for it:
61
+ MagicLink, Ott, and Passkey are **opt-in** featuresthey change the sign-in UX, so you have to
62
+ ask for them:
60
63
 
61
64
  ```sh
62
65
  bin/rails generate authentication --magic-link
66
+ bin/rails generate authentication --ott
67
+ bin/rails generate authentication --passkey
63
68
  ```
64
69
 
65
- It adds a "Sign in with magic link" link to the sign-in page, leading to an email-only form. The
66
- emailed link signs the user in directly; tokens are DB-backed, single-use, and expire after
67
- 20 minutes (`MagicLinkConcern::MAGIC_LINK_EXPIRES_IN`). The magic link flow honors the other
68
- enabled features: locked, unconfirmed, or invitation-pending accounts still can't sign in, and
69
- Trackable records the attempt.
70
+ MagicLink adds a "Sign in with magic link" link to the sign-in page, leading to an email-only
71
+ form. The emailed link signs the user in directly; tokens are DB-backed, single-use, and expire
72
+ after 20 minutes (`MagicLinkConcern::MAGIC_LINK_EXPIRES_IN`).
73
+
74
+ Ott replaces the sign-in form: the user enters only their email address, receives a 6-digit code
75
+ (`OttConcern::OTT_CODE_LENGTH`) by email, and enters it on a second screen — one single-digit
76
+ input per digit with auto-advance and paste/autofill support (plain inline JavaScript, no
77
+ framework required). A "Sign in with password
78
+ instead" link (`/session/new?with_password=1`) toggles back to the classic password form at
79
+ runtime. Codes are DB-backed, single-use, expire after 10 minutes (`OttConcern::OTT_EXPIRES_IN`),
80
+ and are voided after 5 wrong entries (`OttConcern::OTT_MAX_ATTEMPTS`). The password machinery
81
+ (SessionsController#create, Recoverable, Registerable) stays generated and functional — only the
82
+ sign-in UI changes.
83
+
84
+ Passkey adds a "Sign in with a passkey" button to the sign-in page (no email field — the
85
+ browser's own discoverable-credential picker takes its place) plus an authenticated
86
+ `/webauthn_credentials` section where a signed-in user can register and remove passkeys (linked
87
+ from the account page when Registerable is enabled). Unlike every other feature here, this one
88
+ brings a real runtime dependency: the generator adds `gem "webauthn"` to your Gemfile for you (with
89
+ a reminder to run `bundle install`), since ceremony verification is delegated to it. A user can
90
+ register any number of passkeys, each stored as its own row in `webauthn_credentials`.
91
+
92
+ All three flows honor the other enabled features: locked, unconfirmed, or invitation-pending
93
+ accounts still can't sign in, and Trackable records the attempt.
70
94
 
71
95
  Each feature adds a single `include <Feature>Concern` line to `app/models/user.rb`; all of its
72
96
  model behavior lives in `app/models/concerns/<feature>_concern.rb`. Tunables are plain constants in
73
97
  the generated concerns — e.g. `TimeoutableConcern::TIMEOUT_IN`, `LockableConcern::MAXIMUM_ATTEMPTS`,
74
98
  `LockableConcern::UNLOCK_IN`, `ConfirmableConcern::CONFIRMATION_TOKEN_EXPIRES_IN`,
75
- `ValidatableConcern::PASSWORD_LENGTH`, `ValidatableConcern::PASSWORD_MINIMUM_COMPLEXITY` — edit them
76
- there. Concerns keep the model clean.
99
+ `ValidatableConcern::PASSWORD_LENGTH`, `ValidatableConcern::PASSWORD_MINIMUM_COMPLEXITY`,
100
+ `OttConcern::OTT_CODE_LENGTH` — edit them there. Concerns keep the model clean.
77
101
 
78
102
  ### Generated routes
79
103
 
@@ -83,6 +107,9 @@ resources :confirmations, only: %i[ new create show ], param: :token
83
107
  resources :unlocks, only: %i[ new create show ], param: :token
84
108
  resources :invitations, only: %i[ new create edit update ], param: :token
85
109
  resources :magic_links, only: %i[ new create show ], param: :token # with --magic-link
110
+ resource :ott, only: %i[ create edit update ] # with --ott
111
+ resources :webauthn_credentials, only: %i[ index new create destroy ] # with --passkey
112
+ resource :passkey_session, only: %i[ create ] # with --passkey
86
113
  resource :session # from the base generator
87
114
  resources :passwords, param: :token # from the base generator
88
115
  ```
@@ -99,11 +126,6 @@ resources :passwords, param: :token # from the base generator
99
126
  sessions view with versions tailored to the features you selected. Run the generator once, up
100
127
  front — re-running it after you've customized those files will prompt to overwrite them.
101
128
 
102
- ## Future Plans
103
-
104
- - OTT (Email code)
105
- - Passkey
106
-
107
129
  ## Development
108
130
 
109
131
  ```sh
@@ -117,6 +139,53 @@ bundle exec rspec spec/generators/lockable_spec.rb:12 # a single example
117
139
  `spec/dummy` is generated (and gitignored), never hand-maintained, so the request specs always
118
140
  exercise exactly what the templates produce.
119
141
 
142
+ To run the app using the dummy app generated in `spec/dummy`, run `bin/dev`
143
+
144
+ ## Appraisal
145
+
146
+ Install Appraisal dependencies or when a new Appraisal is added, generate the .gemfile
147
+
148
+ ```sh
149
+ bundle exec appraisal generate-install
150
+ ```
151
+
152
+ Run tests with Appraisal
153
+
154
+ ```sh
155
+ bin/appraisal
156
+ ```
157
+
158
+ Run a specific Appraisal test
159
+
160
+ ```sh
161
+ # rails-8.0-json-2
162
+ bundle exec appraisal rails-8.0-json-2 rake spec:generators
163
+ bundle exec appraisal rails-8.0-json-2 rake dummy:prepare
164
+ bundle exec appraisal rails-8.0-json-2 rake spec:requests
165
+ # rails-8.0-json-3
166
+ bundle exec appraisal rails-8.0-json-3 rake spec:generators
167
+ bundle exec appraisal rails-8.0-json-3 rake dummy:prepare
168
+ bundle exec appraisal rails-8.0-json-3 rake spec:requests
169
+ # rails-8.1-json-2
170
+ bundle exec appraisal rails-8.1-json-2 rake spec:generators
171
+ bundle exec appraisal rails-8.1-json-2 rake dummy:prepare
172
+ bundle exec appraisal rails-8.1-json-2 rake spec:requests
173
+ # rails-8.1-json-3
174
+ bundle exec appraisal rails-8.1-json-3 rake spec:generators
175
+ bundle exec appraisal rails-8.1-json-3 rake dummy:prepare
176
+ bundle exec appraisal rails-8.1-json-3 rake spec:requests
177
+ ```
178
+
179
+ ## json 3.0 gem compatibility
180
+
181
+ `json` 3.0 gem removed the `quirks_mode:` keyword and made `JSON.generate`/`JSON.parse`'s second argument keyword-only. Rails' `ActiveSupport::JSON` still calls both with `quirks_mode: true` positionally, so every
182
+ cookie/session read or write throws `ArgumentError` under json 3. `bin/prepare_dummy`
183
+ writes `spec/dummy/config/initializers/json_quirks_mode_compat.rb`, which prepends a shim onto
184
+ `JSON.generate`/`.parse` that strips `quirks_mode` and re-passes remaining options via `**opts`
185
+ (so it works whether the resolved `JSON.parse` still takes a positional options hash, json 2.x,
186
+ or keywords only, json 3.x). It no-ops under json 2.x (`Gem::Version.new(::JSON::VERSION) >=
187
+ Gem::Version.new("3.0")` gates it) and is safe to delete once Rails or json fixes this upstream.
188
+
120
189
  ## License
121
190
 
122
191
  MIT
@@ -12,6 +12,8 @@ require_relative "features/validatable"
12
12
  require_relative "features/lockable"
13
13
  require_relative "features/invitable"
14
14
  require_relative "features/magic_link"
15
+ require_relative "features/ott"
16
+ require_relative "features/passkey"
15
17
 
16
18
  module RailsAuthentication
17
19
  module Generators
@@ -44,6 +46,8 @@ module RailsAuthentication
44
46
  include Features::Lockable
45
47
  include Features::Invitable
46
48
  include Features::MagicLink
49
+ include Features::Ott
50
+ include Features::Passkey
47
51
 
48
52
  source_root File.expand_path("templates", __dir__)
49
53
 
@@ -60,6 +64,17 @@ module RailsAuthentication
60
64
  class_option :magic_link, type: :boolean, default: false,
61
65
  desc: "Add passwordless magic link sign-in (opt-in)"
62
66
 
67
+ # Also opt-in: replaces the sign-in form with an email-only form that
68
+ # emails a 6-digit one-time code, entered on a second screen. Password
69
+ # machinery stays generated and functional.
70
+ class_option :ott, type: :boolean, default: false,
71
+ desc: "Add one-time token (emailed 6-digit code) sign-in (opt-in)"
72
+
73
+ # Also opt-in: WebAuthn passkey sign-in alongside password sign-in.
74
+ # Requires the host app to add the `webauthn` gem itself.
75
+ class_option :passkey, type: :boolean, default: false,
76
+ desc: "Add WebAuthn passkey sign-in (opt-in; requires the webauthn gem)"
77
+
63
78
  def install_base_authentication
64
79
  say "Running Rails' built-in authentication generator", :green
65
80
  Rails::Generators.invoke("rails:authentication", [], behavior: behavior, destination_root: destination_root)
@@ -105,6 +120,14 @@ module RailsAuthentication
105
120
  generate_magic_link if magic_link?
106
121
  end
107
122
 
123
+ def install_ott
124
+ generate_ott if ott?
125
+ end
126
+
127
+ def install_passkey
128
+ generate_passkey if passkey?
129
+ end
130
+
108
131
  # Runs after every feature install so the blank line separates the concern
109
132
  # includes (if any) from the rest of the class body, no matter which features
110
133
  # are enabled.
@@ -135,6 +158,14 @@ module RailsAuthentication
135
158
  options[:magic_link]
136
159
  end
137
160
 
161
+ def ott?
162
+ options[:ott]
163
+ end
164
+
165
+ def passkey?
166
+ options[:passkey]
167
+ end
168
+
138
169
  def include_concern_in_user(concern)
139
170
  inject_into_class "app/models/user.rb", "User", " include #{concern}\n"
140
171
  end
@@ -5,20 +5,21 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Confirmable
7
7
  private
8
- def generate_confirmable
9
- template "app/models/concerns/confirmable_concern.rb"
10
- include_concern_in_user "ConfirmableConcern"
11
- migration_template "db/migrate/add_confirmable_to_users.rb", "db/migrate/add_confirmable_to_users.rb"
12
- template "app/controllers/confirmations_controller.rb"
13
- template "app/views/confirmations/new.html.erb"
14
- route "resources :confirmations, only: %i[ new create show ], param: :token"
15
8
 
16
- if defined?(ActionMailer::Railtie)
17
- template "app/mailers/confirmations_mailer.rb"
18
- template "app/views/confirmations_mailer/confirmation_instructions.html.erb"
19
- template "app/views/confirmations_mailer/confirmation_instructions.text.erb"
20
- end
9
+ def generate_confirmable
10
+ template "app/models/concerns/confirmable_concern.rb"
11
+ include_concern_in_user "ConfirmableConcern"
12
+ migration_template "db/migrate/add_confirmable_to_users.rb", "db/migrate/add_confirmable_to_users.rb"
13
+ template "app/controllers/confirmations_controller.rb"
14
+ template "app/views/confirmations/new.html.erb"
15
+ route "resources :confirmations, only: %i[ new create show ], param: :token"
16
+
17
+ if defined?(ActionMailer::Railtie)
18
+ template "app/mailers/confirmations_mailer.rb"
19
+ template "app/views/confirmations_mailer/confirmation_instructions.html.erb"
20
+ template "app/views/confirmations_mailer/confirmation_instructions.text.erb"
21
21
  end
22
+ end
22
23
  end
23
24
  end
24
25
  end
@@ -5,21 +5,22 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Invitable
7
7
  private
8
- def generate_invitable
9
- template "app/models/concerns/invitable_concern.rb"
10
- include_concern_in_user "InvitableConcern"
11
- migration_template "db/migrate/add_invitable_to_users.rb", "db/migrate/add_invitable_to_users.rb"
12
- template "app/controllers/invitations_controller.rb"
13
- template "app/views/invitations/new.html.erb"
14
- template "app/views/invitations/edit.html.erb"
15
- route "resources :invitations, only: %i[ new create edit update ], param: :token"
16
8
 
17
- if defined?(ActionMailer::Railtie)
18
- template "app/mailers/invitations_mailer.rb"
19
- template "app/views/invitations_mailer/invitation_instructions.html.erb"
20
- template "app/views/invitations_mailer/invitation_instructions.text.erb"
21
- end
9
+ def generate_invitable
10
+ template "app/models/concerns/invitable_concern.rb"
11
+ include_concern_in_user "InvitableConcern"
12
+ migration_template "db/migrate/add_invitable_to_users.rb", "db/migrate/add_invitable_to_users.rb"
13
+ template "app/controllers/invitations_controller.rb"
14
+ template "app/views/invitations/new.html.erb"
15
+ template "app/views/invitations/edit.html.erb"
16
+ route "resources :invitations, only: %i[ new create edit update ], param: :token"
17
+
18
+ if defined?(ActionMailer::Railtie)
19
+ template "app/mailers/invitations_mailer.rb"
20
+ template "app/views/invitations_mailer/invitation_instructions.html.erb"
21
+ template "app/views/invitations_mailer/invitation_instructions.text.erb"
22
22
  end
23
+ end
23
24
  end
24
25
  end
25
26
  end
@@ -5,20 +5,21 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Lockable
7
7
  private
8
- def generate_lockable
9
- template "app/models/concerns/lockable_concern.rb"
10
- include_concern_in_user "LockableConcern"
11
- migration_template "db/migrate/add_lockable_to_users.rb", "db/migrate/add_lockable_to_users.rb"
12
- template "app/controllers/unlocks_controller.rb"
13
- template "app/views/unlocks/new.html.erb"
14
- route "resources :unlocks, only: %i[ new create show ], param: :token"
15
8
 
16
- if defined?(ActionMailer::Railtie)
17
- template "app/mailers/unlocks_mailer.rb"
18
- template "app/views/unlocks_mailer/unlock_instructions.html.erb"
19
- template "app/views/unlocks_mailer/unlock_instructions.text.erb"
20
- end
9
+ def generate_lockable
10
+ template "app/models/concerns/lockable_concern.rb"
11
+ include_concern_in_user "LockableConcern"
12
+ migration_template "db/migrate/add_lockable_to_users.rb", "db/migrate/add_lockable_to_users.rb"
13
+ template "app/controllers/unlocks_controller.rb"
14
+ template "app/views/unlocks/new.html.erb"
15
+ route "resources :unlocks, only: %i[ new create show ], param: :token"
16
+
17
+ if defined?(ActionMailer::Railtie)
18
+ template "app/mailers/unlocks_mailer.rb"
19
+ template "app/views/unlocks_mailer/unlock_instructions.html.erb"
20
+ template "app/views/unlocks_mailer/unlock_instructions.text.erb"
21
21
  end
22
+ end
22
23
  end
23
24
  end
24
25
  end
@@ -8,20 +8,21 @@ module RailsAuthentication
8
8
  # Recoverable rework.
9
9
  module MagicLink
10
10
  private
11
- def generate_magic_link
12
- template "app/models/concerns/magic_link_concern.rb"
13
- include_concern_in_user "MagicLinkConcern"
14
- migration_template "db/migrate/add_magic_link_to_users.rb", "db/migrate/add_magic_link_to_users.rb"
15
- template "app/controllers/magic_links_controller.rb"
16
- template "app/views/magic_links/new.html.erb"
17
- route "resources :magic_links, only: %i[ new create show ], param: :token"
18
11
 
19
- if defined?(ActionMailer::Railtie)
20
- template "app/mailers/magic_links_mailer.rb"
21
- template "app/views/magic_links_mailer/magic_link.html.erb"
22
- template "app/views/magic_links_mailer/magic_link.text.erb"
23
- end
12
+ def generate_magic_link
13
+ template "app/models/concerns/magic_link_concern.rb"
14
+ include_concern_in_user "MagicLinkConcern"
15
+ migration_template "db/migrate/add_magic_link_to_users.rb", "db/migrate/add_magic_link_to_users.rb"
16
+ template "app/controllers/magic_links_controller.rb"
17
+ template "app/views/magic_links/new.html.erb"
18
+ route "resources :magic_links, only: %i[ new create show ], param: :token"
19
+
20
+ if defined?(ActionMailer::Railtie)
21
+ template "app/mailers/magic_links_mailer.rb"
22
+ template "app/views/magic_links_mailer/magic_link.html.erb"
23
+ template "app/views/magic_links_mailer/magic_link.text.erb"
24
24
  end
25
+ end
25
26
  end
26
27
  end
27
28
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsAuthentication
4
+ module Generators
5
+ module Features
6
+ # Opt-in (--ott): one-time token sign-in. The sign-in page becomes an
7
+ # email-only form; a 6-digit code is emailed and entered on a second
8
+ # screen. Codes are DB-backed, single-use, expire after 10 minutes, and
9
+ # are voided after 5 wrong attempts. Password machinery (Recoverable,
10
+ # Registerable, SessionsController#create) is left intact.
11
+ module Ott
12
+ private
13
+
14
+ def generate_ott
15
+ template "app/models/concerns/ott_concern.rb"
16
+ include_concern_in_user "OttConcern"
17
+ migration_template "db/migrate/add_ott_to_users.rb", "db/migrate/add_ott_to_users.rb"
18
+ template "app/controllers/otts_controller.rb"
19
+ template "app/views/otts/edit.html.erb"
20
+ route "resource :ott, only: %i[ create edit update ]"
21
+
22
+ if defined?(ActionMailer::Railtie)
23
+ template "app/mailers/otts_mailer.rb"
24
+ template "app/views/otts_mailer/ott.html.erb"
25
+ template "app/views/otts_mailer/ott.text.erb"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsAuthentication
4
+ module Generators
5
+ module Features
6
+ # Opt-in (--passkey): WebAuthn-based passkey sign-in, in addition to
7
+ # password sign-in. A user may register any number of passkeys
8
+ # (platform authenticators, security keys); sign-in is usernameless —
9
+ # the browser's discoverable-credential picker stands in for an email
10
+ # field. Ceremony verification is delegated to the `webauthn` gem —
11
+ # unlike everything else this gem generates, that's a real runtime
12
+ # dependency, so it's added straight to the host app's Gemfile.
13
+ module Passkey
14
+ private
15
+
16
+ def generate_passkey
17
+ gem "webauthn", comment: "Verifies WebAuthn passkey registration/authentication ceremonies"
18
+ say "Added the `webauthn` gem to your Gemfile — run `bundle install`.", :yellow
19
+
20
+ template "config/initializers/webauthn.rb"
21
+ template "app/models/concerns/passkey_concern.rb"
22
+ include_concern_in_user "PasskeyConcern"
23
+ template "app/models/webauthn_credential.rb"
24
+ migration_template "db/migrate/add_webauthn_id_to_users.rb", "db/migrate/add_webauthn_id_to_users.rb"
25
+ migration_template "db/migrate/create_webauthn_credentials.rb", "db/migrate/create_webauthn_credentials.rb"
26
+ template "app/controllers/webauthn_credentials_controller.rb"
27
+ template "app/controllers/passkey_sessions_controller.rb"
28
+ template "app/views/webauthn_credentials/index.html.erb"
29
+ template "app/views/webauthn_credentials/new.html.erb"
30
+ route "resources :webauthn_credentials, only: %i[ index new create destroy ]"
31
+ route "resource :passkey_session, only: %i[ create ], controller: \"passkey_sessions\""
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -5,20 +5,21 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Recoverable
7
7
  private
8
- # Replaces the base generator's stateless generates_token_for password reset
9
- # with DB-backed, revocable tokens.
10
- def generate_recoverable
11
- template "app/models/concerns/recoverable_concern.rb"
12
- include_concern_in_user "RecoverableConcern"
13
- migration_template "db/migrate/add_recoverable_to_users.rb", "db/migrate/add_recoverable_to_users.rb"
14
- template "app/controllers/passwords_controller.rb", force: true
15
8
 
16
- if defined?(ActionMailer::Railtie)
17
- template "app/mailers/passwords_mailer.rb", force: true
18
- template "app/views/passwords_mailer/reset.html.erb", force: true
19
- template "app/views/passwords_mailer/reset.text.erb", force: true
20
- end
9
+ # Replaces the base generator's stateless generates_token_for password reset
10
+ # with DB-backed, revocable tokens.
11
+ def generate_recoverable
12
+ template "app/models/concerns/recoverable_concern.rb"
13
+ include_concern_in_user "RecoverableConcern"
14
+ migration_template "db/migrate/add_recoverable_to_users.rb", "db/migrate/add_recoverable_to_users.rb"
15
+ template "app/controllers/passwords_controller.rb", force: true
16
+
17
+ if defined?(ActionMailer::Railtie)
18
+ template "app/mailers/passwords_mailer.rb", force: true
19
+ template "app/views/passwords_mailer/reset.html.erb", force: true
20
+ template "app/views/passwords_mailer/reset.text.erb", force: true
21
21
  end
22
+ end
22
23
  end
23
24
  end
24
25
  end
@@ -5,12 +5,13 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Registerable
7
7
  private
8
- def generate_registerable
9
- template "app/controllers/registrations_controller.rb"
10
- template "app/views/registrations/new.html.erb"
11
- template "app/views/registrations/edit.html.erb"
12
- route "resource :registration, only: %i[ new create edit update destroy ]"
13
- end
8
+
9
+ def generate_registerable
10
+ template "app/controllers/registrations_controller.rb"
11
+ template "app/views/registrations/new.html.erb"
12
+ template "app/views/registrations/edit.html.erb"
13
+ route "resource :registration, only: %i[ new create edit update destroy ]"
14
+ end
14
15
  end
15
16
  end
16
17
  end
@@ -5,11 +5,12 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Rememberable
7
7
  private
8
- def generate_rememberable
9
- template "app/models/concerns/rememberable_concern.rb"
10
- include_concern_in_user "RememberableConcern"
11
- migration_template "db/migrate/add_rememberable_to_users.rb", "db/migrate/add_rememberable_to_users.rb"
12
- end
8
+
9
+ def generate_rememberable
10
+ template "app/models/concerns/rememberable_concern.rb"
11
+ include_concern_in_user "RememberableConcern"
12
+ migration_template "db/migrate/add_rememberable_to_users.rb", "db/migrate/add_rememberable_to_users.rb"
13
+ end
13
14
  end
14
15
  end
15
16
  end
@@ -5,12 +5,13 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Timeoutable
7
7
  private
8
- # No migration: inactivity is measured against sessions.updated_at, which the
9
- # base generator's sessions table already has.
10
- def generate_timeoutable
11
- template "app/models/concerns/timeoutable_concern.rb"
12
- include_concern_in_user "TimeoutableConcern"
13
- end
8
+
9
+ # No migration: inactivity is measured against sessions.updated_at, which the
10
+ # base generator's sessions table already has.
11
+ def generate_timeoutable
12
+ template "app/models/concerns/timeoutable_concern.rb"
13
+ include_concern_in_user "TimeoutableConcern"
14
+ end
14
15
  end
15
16
  end
16
17
  end
@@ -5,12 +5,13 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Trackable
7
7
  private
8
- def generate_trackable
9
- template "app/models/concerns/trackable_concern.rb"
10
- include_concern_in_user "TrackableConcern"
11
- template "app/models/user_auth.rb"
12
- migration_template "db/migrate/create_user_auths.rb", "db/migrate/create_user_auths.rb"
13
- end
8
+
9
+ def generate_trackable
10
+ template "app/models/concerns/trackable_concern.rb"
11
+ include_concern_in_user "TrackableConcern"
12
+ template "app/models/user_auth.rb"
13
+ migration_template "db/migrate/create_user_auths.rb", "db/migrate/create_user_auths.rb"
14
+ end
14
15
  end
15
16
  end
16
17
  end
@@ -5,10 +5,11 @@ module RailsAuthentication
5
5
  module Features
6
6
  module Validatable
7
7
  private
8
- def generate_validatable
9
- template "app/models/concerns/validatable_concern.rb"
10
- include_concern_in_user "ValidatableConcern"
11
- end
8
+
9
+ def generate_validatable
10
+ template "app/models/concerns/validatable_concern.rb"
11
+ include_concern_in_user "ValidatableConcern"
12
+ end
12
13
  end
13
14
  end
14
15
  end