action_auth 1.5.1 → 1.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d991a1cd381778da7c3ed0b5ef0878790e81bdd668098eff84937cd4831c0ea
4
- data.tar.gz: 82e3f14dc10fc5b67311ef397fd155d92102bab8ef51b6a3494e760f9ff9463d
3
+ metadata.gz: 2fa128174c9685bef3e348f40b7bfd48c28e26c23ba7c51d3e7088ce039d939a
4
+ data.tar.gz: d92884ccd4e77112736f5f6fd9753def05508d1eb0135cb103af6b7c9a392c62
5
5
  SHA512:
6
- metadata.gz: 77dd6d551f7891f62fb2dd10f1fcc17bd6daca8660edf25e232e05b6e2ca6c4ad83b9e4ce73c1f247c2b770d9e4430eb5d681466844ca09a593f77f2c0e79c24
7
- data.tar.gz: b6247d918574f799757b41345c234dd8cd78545ff81dd49c57528d7994c62d46adf7c0e9c5e6275c4bbf5eb28be27cba4df5cf5d5e1043256b8b317c59b93e43
6
+ metadata.gz: 23bbbe3ed9ae95fadef0eb10c1890d9ec865fff976b3c4837551b0803fcd722b49ecf5bd90ef9778b7f2851b2987ebcee8fdac1b80eb91125fdaaec0e87734a4
7
+ data.tar.gz: 777fabf39c4cc37dda6d487dd2514c46c8ff1a12a63890914e3fe2680d1c23a7542bcb3c9947aeb44c37a93f3206c1cd45a812335194c9b445c8348e81ddaebb
data/README.md CHANGED
@@ -121,11 +121,18 @@ ActionAuth.configure do |config|
121
121
  config.magic_link_enabled = true
122
122
  config.passkey_only = true # Allows sign in with only a passkey
123
123
  config.pwned_enabled = true # defined?(Pwned)
124
+ config.sms_auth_enabled = false
124
125
  config.verify_email_on_sign_in = true
125
126
  config.webauthn_enabled = true # defined?(WebAuthn)
126
127
  config.webauthn_origin = "http://localhost:3000" # or "https://example.com"
127
128
  config.webauthn_rp_name = Rails.application.class.to_s.deconstantize
128
129
  end
130
+
131
+ Rails.application.config.after_initialize do
132
+ ActionAuth.configure do |config|
133
+ config.sms_send_class = SmsSender
134
+ end
135
+ end
129
136
  ```
130
137
 
131
138
  ## Features
@@ -152,6 +159,8 @@ These are the planned features for ActionAuth. The ones that are checked off are
152
159
 
153
160
  ⏳ - OAuth with Google, Facebook, Github, Twitter, etc.
154
161
 
162
+ ✅ - SMS Authentication
163
+
155
164
  ✅ - Have I Been Pwned Integration
156
165
 
157
166
  ✅ - Account Deletion
@@ -245,6 +254,50 @@ an email to the user with a link that will log them in. This is a great way to a
245
254
  without having to remember a password. This is especially useful for users who may not have a password
246
255
  manager or have a hard time remembering passwords.
247
256
 
257
+ ### SMS Authentication
258
+
259
+ SMS Authentication is disabled by default. The purpose of this is to allow users to authenticate
260
+ with a phone number. This is useful and specific to applications that may require a phone number
261
+ instead of an email address for authentication. The basic workflow for this is to register a phone
262
+ number, and then send a code to the phone number. The user will then enter the code to authenticate.
263
+
264
+ No password or email is required for this. I do not recommend enabling this feature for most applications.
265
+
266
+ You must set up your own SMS Provider. This is not included in the gem. You will need to configure the
267
+ `sms_send_class` to send the SMS code. This will expect a class method called `send_code` that will take in the parameters
268
+ `phone_number` and `code`.
269
+
270
+ ```ruby
271
+ require 'twilio-ruby'
272
+
273
+ class SmsSender
274
+ def self.send_code(phone_number, code)
275
+ account_sid = ENV['TWILIO_ACCOUNT_SID']
276
+ auth_token = ENV['TWILIO_AUTH_TOKEN']
277
+ from_number = ENV['TWILIO_PHONE_NUMBER']
278
+
279
+ client = Twilio::REST::Client.new(account_sid, auth_token)
280
+
281
+ client.messages.create(
282
+ from: from_number,
283
+ to: phone_number,
284
+ body: "Your verification code is #{code}"
285
+ )
286
+ end
287
+ end
288
+ ```
289
+
290
+ Since this file could live in the `app/models` or elsewhere, we will need to set its configuration after the Rails
291
+ application has been loaded. This can be done in an initializer.
292
+
293
+ ```ruby
294
+ Rails.application.config.after_initialize do
295
+ ActionAuth.configure do |config|
296
+ config.sms_send_class = SmsSender
297
+ end
298
+ end
299
+ ```
300
+
248
301
  ## Account Deletion
249
302
 
250
303
  Account deletion is a feature that is enabled by default. When a user deletes their account, the account
@@ -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;
@@ -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,6 +6,8 @@ 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
@@ -18,6 +20,8 @@ module ActionAuth
18
20
  @magic_link_enabled = true
19
21
  @passkey_only = true
20
22
  @pwned_enabled = defined?(Pwned)
23
+ @sms_auth_enabled = false
24
+ @sms_send_class = nil
21
25
  @verify_email_on_sign_in = true
22
26
  @webauthn_enabled = defined?(WebAuthn)
23
27
  @webauthn_origin = "http://localhost:3000"
@@ -32,6 +36,10 @@ module ActionAuth
32
36
  @magic_link_enabled == true
33
37
  end
34
38
 
39
+ def sms_auth_enabled?
40
+ @sms_auth_enabled == true
41
+ end
42
+
35
43
  def passkey_only?
36
44
  webauthn_enabled? && @passkey_only == true
37
45
  end
@@ -1,3 +1,3 @@
1
1
  module ActionAuth
2
- VERSION = "1.5.1"
2
+ VERSION = "1.7.0"
3
3
  end
@@ -13,11 +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
20
21
  # end
22
+ #
23
+ # Rails.application.config.after_initialize do
24
+ # ActionAuth.configure do |config|
25
+ # config.sms_send_class = SmsSender
26
+ # end
27
+ # end
21
28
  RUBY
22
29
  end
23
30
  puts "Created config/initializers/action_auth.rb"
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.7.0
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-08-20 00:00:00.000000000 Z
11
+ date: 2024-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '7.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '7.1'
27
27
  - !ruby/object:Gem::Dependency
@@ -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.17
136
+ rubygems_version: 3.5.22
132
137
  signing_key:
133
138
  specification_version: 4
134
139
  summary: A simple Rails engine for authorization.