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 +4 -4
- data/README.md +53 -0
- data/app/assets/stylesheets/action_auth/application.css +4 -0
- data/app/controllers/action_auth/sms_auths/requests_controller.rb +31 -0
- data/app/controllers/action_auth/sms_auths/sign_ins_controller.rb +27 -0
- data/app/models/action_auth/user.rb +9 -1
- data/app/views/action_auth/registrations/new.html.erb +3 -0
- data/app/views/action_auth/sessions/new.html.erb +4 -0
- data/app/views/action_auth/sms_auths/requests/new.html.erb +26 -0
- data/app/views/action_auth/sms_auths/sign_ins/show.html.erb +14 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20241020172209_add_phone_number_to_users.rb +7 -0
- data/lib/action_auth/configuration.rb +8 -0
- data/lib/action_auth/version.rb +1 -1
- data/lib/tasks/action_auth_tasks.rake +7 -0
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2fa128174c9685bef3e348f40b7bfd48c28e26c23ba7c51d3e7088ce039d939a
|
4
|
+
data.tar.gz: d92884ccd4e77112736f5f6fd9753def05508d1eb0135cb103af6b7c9a392c62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
@@ -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
|
data/lib/action_auth/version.rb
CHANGED
@@ -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.
|
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-
|
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.
|
136
|
+
rubygems_version: 3.5.22
|
132
137
|
signing_key:
|
133
138
|
specification_version: 4
|
134
139
|
summary: A simple Rails engine for authorization.
|