action_auth 1.6.0 → 1.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0224e818bf936f4cd37a67bc6634e95d600774962f07796f88b7e66471273a8
4
- data.tar.gz: 95281cb2e34de5fc9f91dcfb1eaca05263ebdedcc5ce4fec14223f27e2d6cf21
3
+ metadata.gz: 4db64b547fb30476de8606114e4a02fd4286c3f1535936847cb253dbe7122cae
4
+ data.tar.gz: 6c6db33a1cd8355ad9f53c22ff6a0e7cefe78f5e79e841694200921724619286
5
5
  SHA512:
6
- metadata.gz: de4c8862b0a7ffdc2688c02d6e5b0cd2120b16d255dc2a63d5dfb2962cd99714ffd77bd80f41d2151f763fc6da44f025cb5092522d12d705db5b712fc88bb654
7
- data.tar.gz: 7a2f3e28ae99f38d58955a3381e6aec6590c0f463b3e7d3d7294221f74bdb3580b2dbeed62d0148aca7346f3a3c7c9a59ce300d5d078b03053b7c08cb2cf3278
6
+ metadata.gz: 850b5731eeb33e46df11d2570df24955f7cabeab7ff31f4df0a87539af781b6f396f656baaa1404720c540d299375eeac2ba349e80d5d7767d08678b21e34091
7
+ data.tar.gz: 8024b8c5fb627c3aadf80d60f7b99860ca6b9a9ed168d6edcc7e3871d0e9ae8ca223a4efe1fbddebade7a3090a2c9daafc19736b6b934eb6ed66d247961e350c
data/README.md CHANGED
@@ -16,12 +16,15 @@ user experience akin to that offered by the well-regarded Devise gem.
16
16
  - [Helper Methods](#helper-methods)
17
17
  - [Restricting and Changing Routes](#restricting-and-changing-routes)
18
18
  5. [Have I Been Pwned](#have-i-been-pwned)
19
- 6. [WebAuthn](#webauthn)
20
- 7. [Within Your Application](#within-your-application)
21
- 8. Customizing
19
+ 6. [Magic Links](#magic-links)
20
+ 7. [SMS Authentication](#sms-authentication)
21
+ 8. [Account Deletion](#account-deletion)
22
+ 9. [WebAuthn](#webauthn)
23
+ 10. [Within Your Application](#within-your-application)
24
+ 11. Customizing
22
25
  - [Sign In Page](https://github.com/kobaltz/action_auth/wiki/Overriding-Sign-In-page-view)
23
- 9. [License](#license)
24
- 10. [Credits](#credits)
26
+ 12. [License](#license)
27
+ 13. [Credits](#credits)
25
28
 
26
29
  ## Breaking Changes
27
30
 
@@ -121,10 +124,19 @@ ActionAuth.configure do |config|
121
124
  config.magic_link_enabled = true
122
125
  config.passkey_only = true # Allows sign in with only a passkey
123
126
  config.pwned_enabled = true # defined?(Pwned)
127
+ config.sms_auth_enabled = false
124
128
  config.verify_email_on_sign_in = true
125
129
  config.webauthn_enabled = true # defined?(WebAuthn)
126
130
  config.webauthn_origin = "http://localhost:3000" # or "https://example.com"
127
131
  config.webauthn_rp_name = Rails.application.class.to_s.deconstantize
132
+
133
+ config.insert_cookie_domain = false
134
+ end
135
+
136
+ Rails.application.config.after_initialize do
137
+ ActionAuth.configure do |config|
138
+ config.sms_send_class = SmsSender
139
+ end
128
140
  end
129
141
  ```
130
142
 
@@ -152,6 +164,8 @@ These are the planned features for ActionAuth. The ones that are checked off are
152
164
 
153
165
  ⏳ - OAuth with Google, Facebook, Github, Twitter, etc.
154
166
 
167
+ ✅ - SMS Authentication
168
+
155
169
  ✅ - Have I Been Pwned Integration
156
170
 
157
171
  ✅ - Account Deletion
@@ -245,6 +259,50 @@ an email to the user with a link that will log them in. This is a great way to a
245
259
  without having to remember a password. This is especially useful for users who may not have a password
246
260
  manager or have a hard time remembering passwords.
247
261
 
262
+ ## SMS Authentication
263
+
264
+ SMS Authentication is disabled by default. The purpose of this is to allow users to authenticate
265
+ with a phone number. This is useful and specific to applications that may require a phone number
266
+ instead of an email address for authentication. The basic workflow for this is to register a phone
267
+ number, and then send a code to the phone number. The user will then enter the code to authenticate.
268
+
269
+ No password or email is required for this. I do not recommend enabling this feature for most applications.
270
+
271
+ You must set up your own SMS Provider. This is not included in the gem. You will need to configure the
272
+ `sms_send_class` to send the SMS code. This will expect a class method called `send_code` that will take in the parameters
273
+ `phone_number` and `code`.
274
+
275
+ ```ruby
276
+ require 'twilio-ruby'
277
+
278
+ class SmsSender
279
+ def self.send_code(phone_number, code)
280
+ account_sid = ENV['TWILIO_ACCOUNT_SID']
281
+ auth_token = ENV['TWILIO_AUTH_TOKEN']
282
+ from_number = ENV['TWILIO_PHONE_NUMBER']
283
+
284
+ client = Twilio::REST::Client.new(account_sid, auth_token)
285
+
286
+ client.messages.create(
287
+ from: from_number,
288
+ to: phone_number,
289
+ body: "Your verification code is #{code}"
290
+ )
291
+ end
292
+ end
293
+ ```
294
+
295
+ Since this file could live in the `app/models` or elsewhere, we will need to set its configuration after the Rails
296
+ application has been loaded. This can be done in an initializer.
297
+
298
+ ```ruby
299
+ Rails.application.config.after_initialize do
300
+ ActionAuth.configure do |config|
301
+ config.sms_send_class = SmsSender
302
+ end
303
+ end
304
+ ```
305
+
248
306
  ## Account Deletion
249
307
 
250
308
  Account deletion is a feature that is enabled by default. When a user deletes their account, the account
@@ -260,6 +318,7 @@ will want to style this to fit your application and have some kind of confirmati
260
318
  <%= button_to "Delete Account", action_auth.users_path, method: :delete %>
261
319
  </p>
262
320
  ```
321
+
263
322
  ## WebAuthn
264
323
 
265
324
  ActionAuth's approach for WebAuthn is simplicity. It is used as a multifactor authentication step,
@@ -54,6 +54,8 @@ body {
54
54
 
55
55
  input[type="text"],
56
56
  input[type="email"],
57
+ input[type="number"],
58
+ input[type="tel"],
57
59
  input[type="password"] {
58
60
  -webkit-text-size-adjust: 100%;
59
61
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
@@ -186,6 +188,8 @@ input[type="password"] {
186
188
 
187
189
  input[type="text"],
188
190
  input[type="email"],
191
+ input[type="number"],
192
+ input[type="tel"],
189
193
  input[type="password"] {
190
194
  color: #d5c4a1;
191
195
  background-color: #282828;
@@ -19,7 +19,9 @@ module ActionAuth
19
19
  else
20
20
  return if check_if_email_is_verified(user)
21
21
  @session = user.sessions.create
22
- cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
22
+ session_token_hash = { value: @session.id, httponly: true }
23
+ session_token_hash[:domain] = :all if ActionAuth.configuration.insert_cookie_domain
24
+ cookies.signed.permanent[:session_token] = session_token_hash
23
25
  redirect_to main_app.root_path, notice: "Signed in successfully"
24
26
  end
25
27
  else
@@ -0,0 +1,31 @@
1
+ module ActionAuth
2
+ class SmsAuths::RequestsController < ApplicationController
3
+ def new
4
+ end
5
+
6
+ def create
7
+ @user = User.find_or_initialize_by(phone_number: params[:phone_number])
8
+ if @user.new_record?
9
+ password = SecureRandom.hex(32)
10
+
11
+ @user.email = "#{SecureRandom.hex(32)}@smsauth"
12
+ @user.password = password
13
+ @user.password_confirmation = password
14
+ @user.verified = false
15
+
16
+ @user.save!
17
+ end
18
+
19
+ code = rand(100_000..999_999)
20
+ @user.update!(sms_code: code, sms_code_sent_at: Time.current)
21
+ cookies.signed[:sms_auth_phone_number] = { value: @user.phone_number, httponly: true }
22
+
23
+ if defined?(ActionAuth.configuration.sms_send_class) &&
24
+ ActionAuth.configuration.sms_send_class.respond_to?(:send_code)
25
+ ActionAuth.configuration.sms_send_class.send_code(@user.phone_number, code)
26
+ end
27
+
28
+ redirect_to sms_auths_sign_ins_path, notice: "Check your phone for a SMS Code."
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ module ActionAuth
2
+ class SmsAuths::SignInsController < ApplicationController
3
+ def show
4
+ @user = ActionAuth::User.find_by(phone_number: params[:phone_number])
5
+ end
6
+
7
+ def create
8
+ user = ActionAuth::User.find_by(
9
+ phone_number: cookies.signed[:sms_auth_phone_number],
10
+ sms_code: params[:sms_code],
11
+ sms_code_sent_at: 5.minutes.ago..Time.current
12
+ )
13
+ if user
14
+ @session = user.sessions.create
15
+ cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
16
+ user.update(
17
+ verified: true,
18
+ sms_code: nil,
19
+ sms_code_sent_at: nil
20
+ )
21
+ redirect_to main_app.root_path, notice: "Signed In"
22
+ else
23
+ redirect_to sign_in_path, alert: "Authentication failed, please try again."
24
+ end
25
+ end
26
+ end
27
+ end
@@ -26,7 +26,15 @@ module ActionAuth
26
26
 
27
27
  validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
28
28
  validates :password, allow_nil: true, length: { minimum: 12 }
29
-
29
+ validates :phone_number,
30
+ allow_nil: true,
31
+ uniqueness: true,
32
+ format: {
33
+ with: /\A\+\d+\z/,
34
+ message: "must be a valid international phone number with digits only after the country code"
35
+ }
36
+
37
+ normalizes :phone_number, with: -> phone_number { phone_number.gsub(/[^+\d]/, '') }
30
38
  normalizes :email, with: -> email { email.strip.downcase }
31
39
 
32
40
  before_validation if: :email_changed?, on: :update do
@@ -39,6 +39,9 @@
39
39
  <% if ActionAuth.configuration.magic_link_enabled? %>
40
40
  <%= link_to "Magic Link", new_magics_requests_path %> |
41
41
  <% end %>
42
+ <% if ActionAuth.configuration.sms_auth_enabled? %>
43
+ <%= link_to "SMS Auth", new_sms_auths_requests_path %> |
44
+ <% end %>
42
45
  <% if ActionAuth.configuration.passkey_only? %>
43
46
  <%= link_to "Passkey", new_sessions_passkey_path %> |
44
47
  <% end %>
@@ -20,6 +20,10 @@
20
20
  <span class="mx-3">or</span>
21
21
  <%= link_to "Magic Link", new_magics_requests_path %>
22
22
  <% end %>
23
+ <% if ActionAuth.configuration.sms_auth_enabled? %>
24
+ <span class="mx-3">or</span>
25
+ <%= link_to "SMS Auth", new_sms_auths_requests_path %> |
26
+ <% end %>
23
27
  <% if ActionAuth.configuration.passkey_only? %>
24
28
  <span class="mx-3">or</span>
25
29
  <%= link_to "Passkey", new_sessions_passkey_path %>
@@ -0,0 +1,26 @@
1
+ <h1>Request SMS Code</h1>
2
+
3
+ <%= form_with(url: sms_auths_requests_path) do |form| %>
4
+ <div class="mb-3">
5
+ <%= form.label :phone_number, style: "display: block" %>
6
+ <%= form.telephone_field :phone_number, required: true, autofocus: true, autocomplete: "mobile" %>
7
+ </div>
8
+
9
+ <div class="mb-3">
10
+ <%= form.submit "Request SMS Code", class: "btn btn-primary" %>
11
+ <span class="mx-3">or</span>
12
+ <%= link_to "Sign In", sign_in_path %>
13
+ <% if ActionAuth.configuration.passkey_only? %>
14
+ <span class="mx-3">or</span>
15
+ <%= link_to "Passkey", new_sessions_passkey_path %>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+
20
+ <div class="mb-3">
21
+ <%= link_to "Sign Up", sign_up_path %> |
22
+ <%= link_to "Reset Password", new_identity_password_reset_path %>
23
+ <% if ActionAuth.configuration.verify_email_on_sign_in %>
24
+ | <%= link_to "Verify Email", identity_email_verification_path %>
25
+ <% end %>
26
+ </div>
@@ -0,0 +1,14 @@
1
+ <h1>Verify SMS Code</h1>
2
+
3
+ <%= form_with(url: sms_auths_sign_ins_path) do |form| %>
4
+ <%= form.hidden_field :phone_number, value: cookies.signed[:sms_auth_phone_number] %>
5
+ <div class="mb-3">
6
+ <%= form.label :sms_code, style: "display: block" %>
7
+ <%= form.number_field :sms_code, required: true, autofocus: true, autocomplete: "one-time-code" %>
8
+ </div>
9
+
10
+ <div class="mb-3">
11
+ <%= form.submit "Sign In", class: "btn btn-primary" %>
12
+ </div>
13
+ <% end %>
14
+
data/config/routes.rb CHANGED
@@ -35,4 +35,11 @@ ActionAuth::Engine.routes.draw do
35
35
  resource :requests, only: [:new, :create]
36
36
  end
37
37
  end
38
+
39
+ if ActionAuth.configuration.sms_auth_enabled?
40
+ namespace :sms_auths do
41
+ resource :sign_ins, only: [:show, :create]
42
+ resource :requests, only: [:new, :create]
43
+ end
44
+ end
38
45
  end
@@ -0,0 +1,7 @@
1
+ class AddPhoneNumberToUsers < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :users, :phone_number, :string
4
+ add_column :users, :sms_code, :string
5
+ add_column :users, :sms_code_sent_at, :datetime
6
+ end
7
+ end
@@ -6,11 +6,14 @@ module ActionAuth
6
6
  attr_accessor :magic_link_enabled
7
7
  attr_accessor :passkey_only
8
8
  attr_accessor :pwned_enabled
9
+ attr_accessor :sms_auth_enabled
10
+ attr_accessor :sms_send_class
9
11
  attr_accessor :verify_email_on_sign_in
10
12
  attr_accessor :webauthn_enabled
11
13
  attr_accessor :webauthn_origin
12
14
  attr_accessor :webauthn_rp_name
13
15
 
16
+ attr_accessor :insert_cookie_domain
14
17
 
15
18
  def initialize
16
19
  @allow_user_deletion = true
@@ -18,10 +21,14 @@ module ActionAuth
18
21
  @magic_link_enabled = true
19
22
  @passkey_only = true
20
23
  @pwned_enabled = defined?(Pwned)
24
+ @sms_auth_enabled = false
25
+ @sms_send_class = nil
21
26
  @verify_email_on_sign_in = true
22
27
  @webauthn_enabled = defined?(WebAuthn)
23
28
  @webauthn_origin = "http://localhost:3000"
24
29
  @webauthn_rp_name = Rails.application.class.to_s.deconstantize
30
+
31
+ @insert_cookie_domain = false
25
32
  end
26
33
 
27
34
  def allow_user_deletion?
@@ -32,6 +39,10 @@ module ActionAuth
32
39
  @magic_link_enabled == true
33
40
  end
34
41
 
42
+ def sms_auth_enabled?
43
+ @sms_auth_enabled == true
44
+ end
45
+
35
46
  def passkey_only?
36
47
  webauthn_enabled? && @passkey_only == true
37
48
  end
@@ -1,3 +1,3 @@
1
1
  module ActionAuth
2
- VERSION = "1.6.0"
2
+ VERSION = "1.7.1"
3
3
  end
@@ -13,10 +13,18 @@ namespace :action_auth do
13
13
  # config.magic_link_enabled = true
14
14
  # config.passkey_only = true # Allows sign in with only a passkey
15
15
  # config.pwned_enabled = true # defined?(Pwned)
16
+ # config.sms_auth_enabled = false
16
17
  # config.verify_email_on_sign_in = true
17
18
  # config.webauthn_enabled = true # defined?(WebAuthn)
18
19
  # config.webauthn_origin = "http://localhost:3000" # or "https://example.com"
19
20
  # config.webauthn_rp_name = Rails.application.class.to_s.deconstantize
21
+ # config.insert_cookie_domain = false
22
+ # end
23
+ #
24
+ # Rails.application.config.after_initialize do
25
+ # ActionAuth.configure do |config|
26
+ # config.sms_send_class = SmsSender
27
+ # end
20
28
  # end
21
29
  RUBY
22
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Kimura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-28 00:00:00.000000000 Z
11
+ date: 2024-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -62,6 +62,8 @@ files:
62
62
  - app/controllers/action_auth/registrations_controller.rb
63
63
  - app/controllers/action_auth/sessions/passkeys_controller.rb
64
64
  - app/controllers/action_auth/sessions_controller.rb
65
+ - app/controllers/action_auth/sms_auths/requests_controller.rb
66
+ - app/controllers/action_auth/sms_auths/sign_ins_controller.rb
65
67
  - app/controllers/action_auth/users_controller.rb
66
68
  - app/controllers/action_auth/webauthn_credential_authentications_controller.rb
67
69
  - app/controllers/action_auth/webauthn_credentials_controller.rb
@@ -83,6 +85,8 @@ files:
83
85
  - app/views/action_auth/sessions/index.html.erb
84
86
  - app/views/action_auth/sessions/new.html.erb
85
87
  - app/views/action_auth/sessions/passkeys/new.html.erb
88
+ - app/views/action_auth/sms_auths/requests/new.html.erb
89
+ - app/views/action_auth/sms_auths/sign_ins/show.html.erb
86
90
  - app/views/action_auth/user_mailer/email_verification.html.erb
87
91
  - app/views/action_auth/user_mailer/email_verification.text.erb
88
92
  - app/views/action_auth/user_mailer/magic_link.html.erb
@@ -99,6 +103,7 @@ files:
99
103
  - db/migrate/20240111125859_add_webauthn_credentials.rb
100
104
  - db/migrate/20240111142545_add_webauthn_id_to_users.rb
101
105
  - db/migrate/20240818032321_add_type_to_webauthn_credentials.rb
106
+ - db/migrate/20241020172209_add_phone_number_to_users.rb
102
107
  - lib/action_auth.rb
103
108
  - lib/action_auth/configuration.rb
104
109
  - lib/action_auth/controllers/helpers.rb
@@ -128,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
133
  - !ruby/object:Gem::Version
129
134
  version: '0'
130
135
  requirements: []
131
- rubygems_version: 3.5.20
136
+ rubygems_version: 3.5.22
132
137
  signing_key:
133
138
  specification_version: 4
134
139
  summary: A simple Rails engine for authorization.