active_authentication 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -1
- data/app/controllers/active_authentication/confirmations_controller.rb +1 -1
- data/app/controllers/active_authentication/magic_links_controller.rb +28 -0
- data/app/controllers/active_authentication/omniauth_callbacks_controller.rb +1 -1
- data/app/controllers/active_authentication/passwords_controller.rb +1 -1
- data/app/controllers/active_authentication/registrations_controller.rb +9 -5
- data/app/controllers/active_authentication/sessions_controller.rb +1 -1
- data/app/controllers/active_authentication/unlocks_controller.rb +1 -1
- data/app/controllers/active_authentication_controller.rb +2 -0
- data/app/mailers/active_authentication/mailer.rb +6 -0
- data/app/views/active_authentication/magic_links/new.html.erb +14 -0
- data/app/views/active_authentication/mailer/magic_link.html.erb +5 -0
- data/app/views/active_authentication/shared/_links.html.erb +4 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/es.yml +15 -0
- data/lib/active_authentication/controller/authenticatable.rb +4 -0
- data/lib/active_authentication/model/magiclinkable.rb +16 -0
- data/lib/active_authentication/model.rb +1 -1
- data/lib/active_authentication/routes.rb +4 -0
- data/lib/active_authentication/version.rb +1 -1
- data/lib/active_authentication.rb +10 -0
- data/lib/generators/active_authentication/install/templates/initializer.rb +12 -0
- data/lib/generators/active_authentication/views/views_generator.rb +1 -1
- 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: 6f71840fc4d08d8eb9ec344aeb3f779e276b09c9812e5a380d1e3455d4d4f29b
|
4
|
+
data.tar.gz: 602d85a21c8cea03d629ca0abfd3698344cb9560e376745aea5d964a6e9b9064
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4307d0af7c4d2a319f2714c1ada81b60956f5a41e7e4d11f17a917e33bf2d2bfa7eeff3d41d3c7ded2a846af2eec55937230f8db6c44c548529d4f21bd4a8a2
|
7
|
+
data.tar.gz: f6e78e92c1298baa72ddf0be06f2bd90553fac04ece61813b0d3829eacc0861d5028ff73200131a4b8e4df51155253f8cd016a79b426c20f50be5d558535a933
|
data/README.md
CHANGED
@@ -13,6 +13,7 @@ A pure Rails authentication solution.
|
|
13
13
|
* Authenticatable: provides the standard email/password authentication. It's the only concern that can't be turned off.
|
14
14
|
* Confirmable: allows users to confirm their email addresses.
|
15
15
|
* Lockable: locks users after a number of failed sign in attempts.
|
16
|
+
* MagicLinkable: allows users to sign in with a magic link.
|
16
17
|
* Omniauthable: allows users to sign up and sign in using a third party service through Omniauth. Turned off by default.
|
17
18
|
* Recoverable: allows users to reset their password.
|
18
19
|
* Registerable: allows users to sign up and edit their profile.
|
@@ -21,7 +22,6 @@ A pure Rails authentication solution.
|
|
21
22
|
|
22
23
|
Planned concerns:
|
23
24
|
|
24
|
-
* MagicLinkable: to allow users to sign in with a magic link.
|
25
25
|
* Invitable: to allow users to invite other users.
|
26
26
|
|
27
27
|
## Installation
|
@@ -98,6 +98,12 @@ Then, to verify if there's an authenticated user, you can use the `user_signed_i
|
|
98
98
|
|
99
99
|
Similarly, you can use `current_user` to access the current authenticated user.
|
100
100
|
|
101
|
+
If you want to close your application entirely, you can add the before action to your application controller, in conjunction with `active_authentication_controller?`, like this:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
before_action :authenticate_user!, unless: :active_authentication_controller?
|
105
|
+
```
|
106
|
+
|
101
107
|
### Omniauthable
|
102
108
|
|
103
109
|
ActiveAuthentication's implementation of OmniAuth allows you to sign in and/or sign up with your third party accounts or sign up with ActiveAuthentication and later connect your third party accounts to ActiveAuthentication's User. To accomplish this, ActiveAuthentication relies on an `Authentication` model which can be created with the `active_authentication:omniauthable` generator.
|
@@ -133,6 +139,21 @@ The sign in and sign up views will show a link to sign in or sign up with each p
|
|
133
139
|
|
134
140
|
When you run the `active_authentication:install` generator, an initializer will be copied to your app at `config/initializers/active_authentication.rb`. There's a section per concern where you can configure certain aspects of their behavior.
|
135
141
|
|
142
|
+
### Customize registration and profile params
|
143
|
+
|
144
|
+
If you add extra fields to your User model, you will likely want to allow users to fill in those fields upon registration or when editing their profile. By default, only email, password and password confirmation are allowed. To change this behavior, just add these lines to your `config/initializers/active_authentication.rb` file:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
ActiveAuthentication.configure do |config|
|
148
|
+
config.profile_params = ->(controller) {
|
149
|
+
controller.params.require(:user).permit(:first_name, :email, :last_name, :password, :password_confirmation) # first_name and last_name were added in this example
|
150
|
+
}
|
151
|
+
config.registration_params = config.profile_params
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
We believe that the configuration of a gem should be placed in just one place. For this gem, it's the initializer. The `profile_params` and `registration_params` take a lambda and that lambda receives a controller. Why a lambda? and why does it take a controller? We could have allowed the params to be just an array of symbols instead of the whole `params.require.permit` call, but in edge cases you might want to post-process the required params, or call tap, or whatever. And to be able to call `params.require.permit`, you need to run this lambda in the context of the registrations controller. That's why the lambda receives the controller.
|
156
|
+
|
136
157
|
### Views
|
137
158
|
|
138
159
|
The default views are good enough to get you started, but you'll want to customize them sooner than later. To copy the default views into your app, run the following command:
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class ActiveAuthentication::MagicLinksController < ActiveAuthenticationController
|
2
|
+
before_action :require_no_authentication
|
3
|
+
before_action :set_user, only: :show
|
4
|
+
|
5
|
+
def new
|
6
|
+
end
|
7
|
+
|
8
|
+
def create
|
9
|
+
@user = User.find_by email: params[:email]
|
10
|
+
@user&.send_magic_link
|
11
|
+
|
12
|
+
redirect_to root_path, notice: t(".success")
|
13
|
+
end
|
14
|
+
|
15
|
+
def show
|
16
|
+
sign_in @user
|
17
|
+
|
18
|
+
redirect_to root_url, notice: t(".success")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def set_user
|
24
|
+
@user = User.find_by_token_for :magic_link, params[:token]
|
25
|
+
|
26
|
+
redirect_to root_url, alert: t(".invalid_token") unless @user.present?
|
27
|
+
end
|
28
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class ActiveAuthentication::RegistrationsController <
|
1
|
+
class ActiveAuthentication::RegistrationsController < ActiveAuthenticationController
|
2
2
|
before_action :require_no_authentication, only: [:new, :create]
|
3
3
|
before_action :authenticate_user!, only: [:edit, :update, :destroy]
|
4
4
|
|
@@ -7,7 +7,7 @@ class ActiveAuthentication::RegistrationsController < ApplicationController
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def create
|
10
|
-
@user = User.new
|
10
|
+
@user = User.new registration_params
|
11
11
|
|
12
12
|
if @user.save
|
13
13
|
sign_in @user
|
@@ -21,7 +21,7 @@ class ActiveAuthentication::RegistrationsController < ApplicationController
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def update
|
24
|
-
if current_user.update(
|
24
|
+
if current_user.update(profile_params)
|
25
25
|
redirect_to edit_profile_path, notice: t(".success")
|
26
26
|
else
|
27
27
|
render :edit, status: :unprocessable_entity
|
@@ -36,7 +36,11 @@ class ActiveAuthentication::RegistrationsController < ApplicationController
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
-
def
|
40
|
-
|
39
|
+
def profile_params
|
40
|
+
ActiveAuthentication.profile_params.call self
|
41
|
+
end
|
42
|
+
|
43
|
+
def registration_params
|
44
|
+
ActiveAuthentication.registration_params.call self
|
41
45
|
end
|
42
46
|
end
|
@@ -6,6 +6,12 @@ module ActiveAuthentication
|
|
6
6
|
mail to: @user.unconfirmed_email
|
7
7
|
end
|
8
8
|
|
9
|
+
def magic_link
|
10
|
+
@token, @user = params[:token], params[:user]
|
11
|
+
|
12
|
+
mail to: @user.email
|
13
|
+
end
|
14
|
+
|
9
15
|
def password_reset_instructions
|
10
16
|
@token, @user = params[:token], params[:user]
|
11
17
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h1 class="text-4xl font-bold"><%=t ".send_magic_link" %></h1>
|
2
|
+
|
3
|
+
<%= form_with url: magic_links_path, data: {turbo: false} do |form| %>
|
4
|
+
<div>
|
5
|
+
<%= form.label :email, t("activerecord.attributes.user.email") %>
|
6
|
+
<%= form.email_field :email %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div>
|
10
|
+
<%= form.submit t(".send_magic_link") %>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<%= render "active_authentication/shared/links" %>
|
@@ -2,6 +2,10 @@
|
|
2
2
|
<p><%= link_to t(".sign_in"), new_session_path %></p>
|
3
3
|
<% end %>
|
4
4
|
|
5
|
+
<% if controller_name != "magic_links" %>
|
6
|
+
<p><%= link_to t(".send_magic_link"), new_magic_link_path %></p>
|
7
|
+
<% end %>
|
8
|
+
|
5
9
|
<% if User.registerable? && controller_name != "registrations" %>
|
6
10
|
<p><%= link_to t(".sign_up"), new_registration_path %></p>
|
7
11
|
<% end %>
|
data/config/locales/en.yml
CHANGED
@@ -16,12 +16,26 @@ en:
|
|
16
16
|
locked: Your account has been locked after %{count} failed attempts. Unlock instructions will be sent to your email.
|
17
17
|
timedout: Your session expired. Sign in again to continue.
|
18
18
|
unauthenticated: You need to sign in or sign up before continuing.
|
19
|
+
magic_links:
|
20
|
+
create:
|
21
|
+
success: Magic link will be sent to your email.
|
22
|
+
new:
|
23
|
+
send_magic_link: Send magic link
|
24
|
+
set_user:
|
25
|
+
invalid_token: Magic link is invalid.
|
26
|
+
show:
|
27
|
+
success: Signed in successfully.
|
19
28
|
mailer:
|
20
29
|
email_confirmation_instructions:
|
21
30
|
confirm_email: Confirm my account
|
22
31
|
confirm_email_below: 'You can confirm your account email by clicking the link below:'
|
23
32
|
hello: Hello, %{email}!
|
24
33
|
subject: Confirmation instructions
|
34
|
+
magic_link:
|
35
|
+
hello: Hello, %{email}!
|
36
|
+
magic_link_below: 'You can sign in to your account by clicking the link below:'
|
37
|
+
sign_in: Sign in
|
38
|
+
subject: Magic link
|
25
39
|
password_reset_instructions:
|
26
40
|
hello: Hello, %{email}!
|
27
41
|
reset_password: Reset your password
|
@@ -76,6 +90,7 @@ en:
|
|
76
90
|
links:
|
77
91
|
reset_password: Reset password
|
78
92
|
send_email_confirmation_instructions: Didn't receive confirmation instructions?
|
93
|
+
send_magic_link: Send me a magic link
|
79
94
|
send_unlock_instructions: Didn't receive unlock instructions?
|
80
95
|
sign_in: Sign in
|
81
96
|
sign_in_or_sign_up_with: Sign in or sign up with %{provider}
|
data/config/locales/es.yml
CHANGED
@@ -16,12 +16,26 @@ es:
|
|
16
16
|
locked: Tu cuenta fue bloqueada después de %{count} intentos fallidos. Te enviaremos un email con las instrucciones de desbloqueo.
|
17
17
|
timedout: Tu sesión expiró. Iniciá sesión nuevamente para continuar.
|
18
18
|
unauthenticated: Tenés que iniciar sesión antes de continuar.
|
19
|
+
magic_links:
|
20
|
+
create:
|
21
|
+
success: Te enviaremos un email con un enlace mágico para iniciar sesión.
|
22
|
+
new:
|
23
|
+
send_magic_link: Enviar enlace mágico
|
24
|
+
set_user:
|
25
|
+
invalid_token: El enlace mágico es inválido.
|
26
|
+
show:
|
27
|
+
success: Inicio de sesión existoso.
|
19
28
|
mailer:
|
20
29
|
email_confirmation_instructions:
|
21
30
|
confirm_email: Confirmar mi cuenta
|
22
31
|
confirm_email_below: 'Podés confirmar tu cuenta haciendo click en el siguiente link:'
|
23
32
|
hello: Hola, %{email}!
|
24
33
|
subject: Instrucciones de confirmación
|
34
|
+
magic_link:
|
35
|
+
hello: Hola, %{email}!
|
36
|
+
magic_link_below: 'Podés iniciar sesión haciendo click en el siguiente link:'
|
37
|
+
sign_in: Iniciar sesión
|
38
|
+
subject: Enlace mágico
|
25
39
|
password_reset_instructions:
|
26
40
|
hello: Hola, %{email}!
|
27
41
|
reset_password: Recuperar contraseña
|
@@ -76,6 +90,7 @@ es:
|
|
76
90
|
links:
|
77
91
|
reset_password: Recuperar contraseña
|
78
92
|
send_email_confirmation_instructions: "¿No recibiste las instrucciones de confirmación?"
|
93
|
+
send_magic_link: Enviarme un enlace mágico
|
79
94
|
send_unlock_instructions: "¿No recibiste las instrucciones de desbloqueo?"
|
80
95
|
sign_in: Iniciar sesión
|
81
96
|
sign_in_or_sign_up_with: Iniciar sesión o crear una cuenta con %{provider}
|
@@ -8,6 +8,10 @@ module ActiveAuthentication
|
|
8
8
|
helper_method :user_signed_in?
|
9
9
|
end
|
10
10
|
|
11
|
+
def active_authentication_controller?
|
12
|
+
is_a? ::ActiveAuthenticationController
|
13
|
+
end
|
14
|
+
|
11
15
|
def authenticate_user!
|
12
16
|
redirect_to new_session_path, alert: t("active_authentication.failure.unauthenticated") unless user_signed_in?
|
13
17
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveAuthentication
|
2
|
+
module Model
|
3
|
+
module Magiclinkable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
generates_token_for :magic_link, expires_in: ActiveAuthentication.magic_link_token_expires_in
|
8
|
+
end
|
9
|
+
|
10
|
+
def send_magic_link
|
11
|
+
token = generate_token_for :magic_link
|
12
|
+
ActiveAuthentication::Mailer.with(token: token, user: self).magic_link.deliver
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -2,7 +2,7 @@ module ActiveAuthentication
|
|
2
2
|
module Model
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
CONCERNS = %i[authenticatable confirmable lockable omniauthable recoverable registerable timeoutable trackable]
|
5
|
+
CONCERNS = %i[authenticatable confirmable lockable magiclinkable omniauthable recoverable registerable timeoutable trackable]
|
6
6
|
|
7
7
|
class_methods do
|
8
8
|
def authenticates_with(*concerns)
|
@@ -22,6 +22,10 @@ module ActionDispatch::Routing
|
|
22
22
|
resources :unlocks, param: :token, only: [:new, :create, :show]
|
23
23
|
end
|
24
24
|
|
25
|
+
def magiclinkable
|
26
|
+
resources :magic_links, param: :token, only: [:new, :create, :show]
|
27
|
+
end
|
28
|
+
|
25
29
|
def omniauthable
|
26
30
|
get "auth/:provider", to: "omniauth_callbacks#pass", as: :omniauth
|
27
31
|
get "auth/:provider/callback", to: "omniauth_callbacks#create", as: :omniauth_callback
|
@@ -20,6 +20,7 @@ module ActiveAuthentication
|
|
20
20
|
autoload :Authenticatable, "active_authentication/model/authenticatable"
|
21
21
|
autoload :Confirmable, "active_authentication/model/confirmable"
|
22
22
|
autoload :Lockable, "active_authentication/model/lockable"
|
23
|
+
autoload :Magiclinkable, "active_authentication/model/magiclinkable"
|
23
24
|
autoload :Omniauthable, "active_authentication/model/omniauthable"
|
24
25
|
autoload :Recoverable, "active_authentication/model/recoverable"
|
25
26
|
autoload :Registerable, "active_authentication/model/registerable"
|
@@ -41,12 +42,21 @@ module ActiveAuthentication
|
|
41
42
|
config_accessor :unlock_token_expires_in, default: 24.hours
|
42
43
|
config_accessor :max_failed_attempts, default: 10
|
43
44
|
|
45
|
+
# magiclinkable
|
46
|
+
config_accessor :magic_link_token_expires_in, default: 24.hours
|
47
|
+
|
44
48
|
# omniauthable
|
45
49
|
config_accessor :omniauth_providers, default: []
|
46
50
|
|
47
51
|
# recoverable
|
48
52
|
config_accessor :password_reset_token_expires_in, default: 1.hour
|
49
53
|
|
54
|
+
# registerable
|
55
|
+
config_accessor :profile_params, default: ->(controller) {
|
56
|
+
controller.params.require(:user).permit(:email, :password, :password_confirmation)
|
57
|
+
}
|
58
|
+
config_accessor :registration_params, default: profile_params
|
59
|
+
|
50
60
|
# timeoutable
|
51
61
|
config_accessor :timeout_in, default: 30.minutes
|
52
62
|
end
|
@@ -9,9 +9,21 @@ ActiveAuthentication.configure do |config|
|
|
9
9
|
# config.unlock_token_expires_in = 24.hours
|
10
10
|
# config.max_failed_attempts = 10
|
11
11
|
|
12
|
+
# configuration for the magiclinkable concern
|
13
|
+
# config.magic_link_token_expires_in = 24.hours
|
14
|
+
|
12
15
|
# configuration for the recoverable concern
|
13
16
|
# config.password_reset_token_expires_in = 1.hour
|
14
17
|
|
18
|
+
# configuration for the registerable concern
|
19
|
+
# config_accessor :profile_params, default: ->(controller) {
|
20
|
+
# controller.params.require(:user).permit(:email, :password, :password_confirmation)
|
21
|
+
# }
|
22
|
+
# by default the registration_params take the same lambda as the profile_params. if you redefine the
|
23
|
+
# profile_params setting, you will need to uncomment this line as otherwise it will take the default value,
|
24
|
+
# previously defined.
|
25
|
+
# config_accessor :registration_params, default: profile_params
|
26
|
+
|
15
27
|
# configuration for the timeoutable concern
|
16
28
|
# config.timeout_in = 30.minutes
|
17
29
|
end
|
@@ -3,7 +3,7 @@ class ActiveAuthentication::ViewsGenerator < Rails::Generators::Base
|
|
3
3
|
|
4
4
|
desc "Generates active_authentication's views."
|
5
5
|
|
6
|
-
class_option :views, aliases: "-v", type: :array, desc: "Views to generate (available: confirmations, mailer, passwords, registrations, sessions, shared, unlocks)"
|
6
|
+
class_option :views, aliases: "-v", type: :array, desc: "Views to generate (available: confirmations, magic_links, mailer, passwords, registrations, sessions, shared, unlocks)"
|
7
7
|
|
8
8
|
def copy_views
|
9
9
|
if options[:views]
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_authentication
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patricio Mac Adden
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-11 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.0'
|
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.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -49,14 +49,18 @@ files:
|
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
51
51
|
- app/controllers/active_authentication/confirmations_controller.rb
|
52
|
+
- app/controllers/active_authentication/magic_links_controller.rb
|
52
53
|
- app/controllers/active_authentication/omniauth_callbacks_controller.rb
|
53
54
|
- app/controllers/active_authentication/passwords_controller.rb
|
54
55
|
- app/controllers/active_authentication/registrations_controller.rb
|
55
56
|
- app/controllers/active_authentication/sessions_controller.rb
|
56
57
|
- app/controllers/active_authentication/unlocks_controller.rb
|
58
|
+
- app/controllers/active_authentication_controller.rb
|
57
59
|
- app/mailers/active_authentication/mailer.rb
|
58
60
|
- app/views/active_authentication/confirmations/new.html.erb
|
61
|
+
- app/views/active_authentication/magic_links/new.html.erb
|
59
62
|
- app/views/active_authentication/mailer/email_confirmation_instructions.html.erb
|
63
|
+
- app/views/active_authentication/mailer/magic_link.html.erb
|
60
64
|
- app/views/active_authentication/mailer/password_reset_instructions.html.erb
|
61
65
|
- app/views/active_authentication/mailer/unlock_instructions.html.erb
|
62
66
|
- app/views/active_authentication/passwords/edit.html.erb
|
@@ -81,6 +85,7 @@ files:
|
|
81
85
|
- lib/active_authentication/model/authenticatable.rb
|
82
86
|
- lib/active_authentication/model/confirmable.rb
|
83
87
|
- lib/active_authentication/model/lockable.rb
|
88
|
+
- lib/active_authentication/model/magiclinkable.rb
|
84
89
|
- lib/active_authentication/model/omniauthable.rb
|
85
90
|
- lib/active_authentication/model/recoverable.rb
|
86
91
|
- lib/active_authentication/model/registerable.rb
|
@@ -116,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
116
121
|
- !ruby/object:Gem::Version
|
117
122
|
version: '0'
|
118
123
|
requirements: []
|
119
|
-
rubygems_version: 3.5.
|
124
|
+
rubygems_version: 3.5.22
|
120
125
|
signing_key:
|
121
126
|
specification_version: 4
|
122
127
|
summary: A pure Rails authentication solution
|