devise-passkeys 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,16 +7,16 @@ module Devise
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- include Devise::Passkeys::Controllers::Concerns::PasskeyReauthentication
10
+ include Devise::Passkeys::Controllers::Concerns::Reauthentication
11
11
  include Devise::Passkeys::Controllers::Concerns::ReauthenticationChallenge
12
12
  include Warden::WebAuthn::AuthenticationInitiationHelpers
13
13
  include Warden::WebAuthn::RegistrationHelpers
14
- include Warden::WebAuthn::StrategyHelpers
15
14
 
16
15
  prepend_before_action :authenticate_scope!
17
16
  before_action :ensure_at_least_one_passkey, only: %i[new_destroy_challenge destroy]
18
17
  before_action :find_passkey, only: %i[new_destroy_challenge destroy]
19
18
 
19
+ before_action :verify_credential_integrity, only: [:create]
20
20
  before_action :verify_passkey_challenge, only: [:create]
21
21
  before_action :verify_reauthentication_token, only: %i[create destroy]
22
22
 
@@ -93,18 +93,17 @@ module Devise
93
93
  { id: resource.webauthn_id, name: resource.email }
94
94
  end
95
95
 
96
+ def verify_credential_integrity
97
+ return render_credential_missing_or_could_not_be_parsed_error if parsed_credential.nil?
98
+ rescue JSON::JSONError, TypeError
99
+ return render_credential_missing_or_could_not_be_parsed_error
100
+ end
101
+
96
102
  def verify_passkey_challenge
97
- if parsed_credential.nil?
98
- render json: { message: find_message(:credential_missing_or_could_not_be_parsed) }, status: :bad_request
99
- delete_registration_challenge
100
- return false
101
- end
102
- begin
103
- @webauthn_credential = verify_registration(relying_party: relying_party)
104
- rescue ::WebAuthn::Error => e
105
- error_key = Warden::WebAuthn::ErrorKeyFinder.webauthn_error_key(exception: e)
106
- render json: { message: find_message(error_key) }, status: :bad_request
107
- end
103
+ @webauthn_credential = verify_registration(relying_party: relying_party)
104
+ rescue ::WebAuthn::Error => e
105
+ error_key = Warden::WebAuthn::ErrorKeyFinder.webauthn_error_key(exception: e)
106
+ render json: { message: find_message(error_key) }, status: :bad_request
108
107
  end
109
108
 
110
109
  def passkey_params
@@ -134,6 +133,12 @@ module Devise
134
133
  def reauthentication_params
135
134
  params.require(:passkey).permit(:reauthentication_token)
136
135
  end
136
+
137
+ def render_credential_missing_or_could_not_be_parsed_error
138
+ render json: { message: find_message(:credential_missing_or_could_not_be_parsed) }, status: :bad_request
139
+ delete_registration_challenge
140
+ return false
141
+ end
137
142
  end
138
143
  end
139
144
  end
@@ -3,14 +3,44 @@
3
3
  module Devise
4
4
  module Passkeys
5
5
  module Controllers
6
+ # This concern is responsible for handling reauthentication.
7
+ # It should be included in any controller that handles reauthentication, and defines:
8
+ #
9
+ # - Useful methods to assist with the reauthentication process
10
+ # - Concerns that are required to complete the reauthentication process
11
+ # - Helper modules from `Warden::WebAuthn` that are required to complete the reauthentication process
12
+ #
13
+ # **Note**: the implementing controller **must** define a `relying_party` method in order for
14
+ # reauthentications to work.
15
+ #
16
+ # @example
17
+ # class ReauthenticationController < ApplicationController
18
+ # include Devise::Passkeys::Controllers::ReauthenticationControllerConcern
19
+ #
20
+ # def relying_party
21
+ # WebAuthn::RelyingParty.new
22
+ # end
23
+ # end
24
+ #
25
+ # The `authenticate_scope!` is called as a `before_action` to verify the authentication and set the
26
+ # `resource` for the controller.
27
+ #
28
+ # Likewise, `Warden::WebAuthn::RackHelpers#set_relying_party_in_request_env` is a `before_action` to ensure that the relying party is set in the
29
+ # `request.env` before the Warden strategy is executed
30
+ #
31
+ # @see relying_party
32
+ # @see Devise::Passkeys::Controllers::Concerns::ReauthenticationChallenge
33
+ # @see Devise::Passkeys::Controllers::Concerns::Reauthentication
34
+ # @see Warden::WebAuthn::StrategyHelpers
35
+ # @see Warden::WebAuthn::RackHelpers
6
36
  module ReauthenticationControllerConcern
7
37
  extend ActiveSupport::Concern
8
38
 
9
39
  included do
10
- include Devise::Passkeys::Controllers::Concerns::PasskeyReauthentication
40
+ include Devise::Passkeys::Controllers::Concerns::Reauthentication
11
41
  include Devise::Passkeys::Controllers::Concerns::ReauthenticationChallenge
12
42
  include Warden::WebAuthn::AuthenticationInitiationHelpers
13
- include Warden::WebAuthn::StrategyHelpers
43
+ include Warden::WebAuthn::RackHelpers
14
44
 
15
45
  prepend_before_action :authenticate_scope!
16
46
 
@@ -27,6 +57,14 @@ module Devise
27
57
  end
28
58
  end
29
59
 
60
+ # A controller action that stores the reauthentication challenge in session
61
+ # and renders the options for authentication from `webauthn-ruby`.
62
+ #
63
+ # The response is rendered as JSON, with a status of `200 OK`.
64
+ #
65
+ # @see Devise::Passkeys::Controllers::Concerns::ReauthenticationChallenge#store_reauthentication_challenge_in_session
66
+ # @see Warden::WebAuthn::AuthenticationInitiationHelpers#generate_authentication_options
67
+ # @see Warden::WebAuthn::RackHelpers#set_relying_party_in_request_env
30
68
  def new_challenge
31
69
  options_for_authentication = generate_authentication_options(relying_party: relying_party,
32
70
  options: { allow: resource.passkeys.pluck(:external_id) })
@@ -36,6 +74,24 @@ module Devise
36
74
  render json: options_for_authentication
37
75
  end
38
76
 
77
+ # A controller action that:
78
+ #
79
+ # 1. Uses the `warden` strategy to authenticate the current user with the defined strategy
80
+ # 2. Calls `sign_in` with `event: :passkey_reauthentication` to verify that the user can authenticate
81
+ # 3. Stores the reauthentication token in the session
82
+ # 4. Renders a JSON object with the reauthentication token
83
+ # 5. Ensures that the reauthentication challenge from the session, regardless of any errors
84
+ #
85
+ # @example
86
+ # {"reauthentication_token": "abcd1234"}
87
+ #
88
+ # `prepare_params` is called as a `before_action` to prepare the passkey credential for use by the
89
+ # Warden strategy.
90
+ #
91
+ # Optionally accepts a block that will be executed after the user has been reauthenticated.
92
+ # @see strategy
93
+ # @see Devise::Passkeys::Controllers::Concerns::Reauthentication#store_reauthentication_token_in_session
94
+ # @see prepare_params
39
95
  def reauthenticate
40
96
  sign_out(resource)
41
97
  self.resource = warden.authenticate!(strategy, auth_options)
@@ -51,12 +107,18 @@ module Devise
51
107
 
52
108
  protected
53
109
 
110
+ # @!visibility public
111
+ # Prepares the request parameters for use by the Warden strategy
54
112
  def prepare_params
55
113
  request.params[resource_name] = ActionController::Parameters.new({
56
114
  passkey_credential: params[:passkey_credential]
57
115
  })
58
116
  end
59
117
 
118
+ # @!visibility public
119
+ # A method that can be overridden to customize the Warden stratey used.
120
+ # @return [Symbol] The key that identifies which `Warden` strategy will be used to handle the
121
+ # authentication flow for the reauthentication. Defaults to `:passkey_reauthentication`
60
122
  def strategy
61
123
  :passkey_reauthentication
62
124
  end
@@ -69,8 +131,12 @@ module Devise
69
131
  session.delete(passkey_reauthentication_challenge_session_key)
70
132
  end
71
133
 
72
- def set_relying_party_in_request_env
73
- raise "need to define relying_party for this SessionsController"
134
+ # @!visibility public
135
+ # @abstract
136
+ # The method that returns the `WebAuthn::RelyingParty` for this request.
137
+ # @return [WebAuthn::RelyingParty] when overridden, this method should return a `WebAuthn::RelyingParty` instance
138
+ def relying_party
139
+ raise NoMethodError, "need to define relying_party for this #{self.class.name}"
74
140
  end
75
141
  end
76
142
  end
@@ -3,11 +3,43 @@
3
3
  module Devise
4
4
  module Passkeys
5
5
  module Controllers
6
+ # This concern should be included in any controller that handles
7
+ # user (`resource`) registration management (ie: signup/deleting an account),
8
+ # and defines:
9
+ #
10
+ # - Useful methods and before filters to streamline user (`resource`) registration management using session variables
11
+ # - Controller actions for:
12
+ # - Issuing a new WebAuthn challenge
13
+ # - A `create` action that creates a passkey if the user (`resource`) has been persisted
14
+ # - Helper modules from `Warden::WebAuthn` that are required to complete the registration process
15
+ #
16
+ # The `registration_user_id_key` and `registration_challenge_key` are defined
17
+ # using the `resource_name`, to keep the generated IDs unique between resources
18
+ # during the registration process.
19
+ #
20
+ # A `raw_credential` method is provided to streamline access to
21
+ # `passkey_params[:passkey_credential]`.
22
+ #
23
+ # **Note**: the implementing controller **must** define a `relying_party` method in order for
24
+ # registrations to work.
25
+ #
26
+ # @example
27
+ # class RegistrationsController < ApplicationController
28
+ # include Devise::Passkeys::Controllers::RegistrationsControllerConcern
29
+ #
30
+ # def relying_party
31
+ # WebAuthn::RelyingParty.new
32
+ # end
33
+ # end
34
+ #
35
+ #
36
+ # @see Devise::Passkeys::Controllers::Concerns::Reauthentication
37
+ # @see Warden::WebAuthn::RegistrationHelpers
6
38
  module RegistrationsControllerConcern
7
39
  extend ActiveSupport::Concern
8
40
 
9
41
  included do
10
- include Devise::Passkeys::Controllers::Concerns::PasskeyReauthentication
42
+ include Devise::Passkeys::Controllers::Concerns::Reauthentication
11
43
  include Warden::WebAuthn::RegistrationHelpers
12
44
 
13
45
  before_action :require_no_authentication, only: [:new_challenge]
@@ -30,6 +62,20 @@ module Devise
30
62
  end
31
63
  end
32
64
 
65
+ # This controller action issues a new challenge for the registration handshake.
66
+ #
67
+ # The challenge is stored in a session variable, and renders the WebAuthn
68
+ # registration options as a JSON response.
69
+ #
70
+ # The following before filters are called:
71
+ #
72
+ # - `require_no_authentication`
73
+ # - `require_email_and_passkey_label`
74
+ #
75
+ # @see DeviseController#require_no_authentication
76
+ # @see require_email_and_passkey_label
77
+ # @see Warden::WebAuthn#generate_registration_options
78
+ # @see https://github.com/cedarcode/webauthn-ruby#initiation-phase
33
79
  def new_challenge
34
80
  options_for_registration = generate_registration_options(
35
81
  relying_party: relying_party,
@@ -42,15 +88,48 @@ module Devise
42
88
  render json: options_for_registration
43
89
  end
44
90
 
91
+ # This controller action creates a new user (`resource`), using the given
92
+ # email & passkey. It:
93
+ #
94
+ # 1. calls the parent class's `#create` method
95
+ # 2. calls `#create_passkey_for_resource` to finish creating the passkey
96
+ # if the user (`resource`) was actually persisted
97
+ # 3. Finishes the rest of the parent class's `#create` method
98
+ #
99
+ #
100
+ # The following before actions are called:
101
+ #
102
+ # - `require_email_and_passkey_label`
103
+ # - `verify_passkey_registration_challenge`
104
+ # - `configure_sign_up_params`
105
+ #
106
+ # @see require_email_and_passkey_label
107
+ # @see verify_passkey_registration_challenge
108
+ # @see configure_sign_up_params
109
+ # @see create_passkey_for_resource
45
110
  def create
46
111
  super do |resource|
47
- create_resource_and_passkey(resource: resource)
112
+ create_passkey_for_resource(resource: resource)
48
113
  end
49
114
  end
50
115
 
51
116
  protected
52
117
 
53
- def create_resource_and_passkey(resource:)
118
+ # @!visibility public
119
+ #
120
+ # Creates a passkey for given user (`resource`).
121
+ #
122
+ # The method tests that the user (`resource`) is in the database
123
+ # before saving the passkey for the given user (`resource`).
124
+ #
125
+ #
126
+ # This method also ensures that the generated WebAuthn User ID is deleted from the session to prevent
127
+ # data leaks.
128
+ #
129
+ #
130
+ # @yield [resource, passkey] The provided `resource` and the newly created passkey.
131
+ # @see create_passkey
132
+ def create_passkey_for_resource(resource:)
54
133
  return unless resource.persisted?
55
134
 
56
135
  passkey = create_passkey(resource: resource)
@@ -59,6 +138,17 @@ module Devise
59
138
  delete_registration_user_id!
60
139
  end
61
140
 
141
+ # @!visibility public
142
+ #
143
+ # Generates a passkey for the given `resource`, using the `resource.passkeys.create!`
144
+ # method with the following attributes:
145
+ #
146
+ # - `label`: The `passkey_params[:passkey_label]`
147
+ # - `public_key`: The `@webauthn_credential.public_key`
148
+ # - `external_id`: The credential ID, strictly encoded as a Base 64 string
149
+ # - `sign_count`: The `@webauthn_credential.sign_count`
150
+ # - `last_used_at`: The current time, since this is the first time the passkey is being used
151
+ #
62
152
  def create_passkey(resource:)
63
153
  resource.passkeys.create!(
64
154
  label: passkey_params[:passkey_label],
@@ -69,29 +159,61 @@ module Devise
69
159
  )
70
160
  end
71
161
 
162
+ # @!visibility public
163
+ #
164
+ # Verifies that the given reauthentication token matches the
165
+ # expected value stored in the session.
166
+ #
167
+ # If the reauthentication token is not valid,
168
+ # a `400 Bad Request` JSON response is rendered.
169
+ #
170
+ # @example
171
+ # {"error": "Please reauthenticate to continue."}
172
+ #
173
+ # @see reauthentication_params
174
+ # @see Devise::Passkeys::Controllers::Concerns::Reauthentication#valid_reauthentication_token?
72
175
  def verify_reauthentication_token
73
176
  return if valid_reauthentication_token?(given_reauthentication_token: reauthentication_params[:reauthentication_token])
74
177
 
75
178
  render json: { error: find_message(:not_reauthenticated) }, status: :bad_request
76
179
  end
77
180
 
181
+ # @!visibility public
182
+ # The subset of parameters used when verifying a reauthentication_token
78
183
  def reauthentication_params
79
- params.require(:user).permit(:reauthentication_token)
184
+ params.require(resource_name).permit(:reauthentication_token)
80
185
  end
81
186
 
187
+ # @!visibility public
188
+ # An override of `DeviseController`'s implementation, to circumvent the
189
+ # `update_with_password` method
190
+ # @see DeviseController#update_resource
82
191
  def update_resource(resource, params)
83
192
  resource.update(params)
84
193
  end
85
194
 
86
- # Override if you need to exclude certain external IDs
195
+ # @!visibility public
196
+ # Override this method if you need to exclude certain WebAuthn credentials
197
+ # from a registration request.
198
+ # @see new_challenge
199
+ # @see https://github.com/cedarcode/webauthn-ruby#initiation-phase
87
200
  def exclude_external_ids_for_registration
88
201
  []
89
202
  end
90
203
 
204
+ # @!visibility public
205
+ # The subset of parameters used when verifying the passkey
91
206
  def passkey_params
92
207
  params.require(resource_name).permit(:passkey_label, :passkey_credential)
93
208
  end
94
209
 
210
+ # @!visibility public
211
+ # Verifies that the `sign_up_params` has an `:email` and `:passkey_label`.
212
+ #
213
+ # If either is missing or blank, a `400 Bad Request` JSON response is rendered.
214
+ #
215
+ # @example
216
+ # {"error": "Please enter your email address."}
95
217
  def require_email_and_passkey_label
96
218
  if sign_up_params[:email].blank?
97
219
  render json: { message: find_message(:email_missing) }, status: :bad_request
@@ -106,6 +228,18 @@ module Devise
106
228
  true
107
229
  end
108
230
 
231
+ # @!visibility public
232
+ # Verifies the registration challenge is correct.
233
+ #
234
+ # If the challenge failed, a `400 Bad Request` JSON
235
+ # response is rendered.
236
+ #
237
+ # @example
238
+ # {"error": "Please try a different passkey."}
239
+ #
240
+ # @see Warden::WebAuthn::RegistrationHelpers#verify_registration
241
+ # @see https://github.com/cedarcode/webauthn-ruby#verification-phase
242
+ # @see Warden::WebAuthn::ErrorKeyFinder#webauthn_error_key
109
243
  def verify_passkey_registration_challenge
110
244
  @webauthn_credential = verify_registration(relying_party: relying_party)
111
245
  rescue ::WebAuthn::Error => e
@@ -113,12 +247,17 @@ module Devise
113
247
  render json: { message: find_message(error_key) }, status: :bad_request
114
248
  end
115
249
 
116
- # If you have extra params to permit, append them to the sanitizer.
250
+ # @!visibility public
251
+ # Adds the generated WebAuthn User ID to `devise_parameter_sanitizer`'s permitted keys
117
252
  def configure_sign_up_params
118
- params[:user][:webauthn_id] = registration_user_id
253
+ params[resource_name][:webauthn_id] = registration_user_id
119
254
  devise_parameter_sanitizer.permit(:sign_up, keys: [:webauthn_id])
120
255
  end
121
256
 
257
+ # @!visibility public
258
+ # Prepares the user details for a WebAuthn registration request
259
+ # @see new_challenge
260
+ # @see https://github.com/cedarcode/webauthn-ruby#initiation-phase
122
261
  def user_details_for_registration
123
262
  store_registration_user_id
124
263
  { id: registration_user_id, name: sign_up_params[:email] }
@@ -8,7 +8,7 @@ module Devise
8
8
 
9
9
  included do
10
10
  include Warden::WebAuthn::AuthenticationInitiationHelpers
11
- include Warden::WebAuthn::StrategyHelpers
11
+ include Warden::WebAuthn::RackHelpers
12
12
 
13
13
  # Prepending is crucial to ensure that the relying party is set in the
14
14
  # request.env before the strategy is executed
@@ -29,8 +29,8 @@ module Devise
29
29
 
30
30
  protected
31
31
 
32
- def set_relying_party_in_request_env
33
- raise "need to define relying_party for this SessionsController"
32
+ def relying_party
33
+ raise NoMethodError, "need to define relying_party for this #{self.class.name}"
34
34
  end
35
35
  end
36
36
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "controllers/concerns/passkey_reauthentication"
3
+ require_relative "controllers/concerns/reauthentication"
4
4
  require_relative "controllers/concerns/reauthentication_challenge"
5
5
  require_relative "controllers/sessions_controller_concern"
6
6
  require_relative "controllers/registrations_controller_concern"
@@ -9,6 +9,60 @@ require_relative "controllers/passkeys_controller_concern"
9
9
 
10
10
  module Devise
11
11
  module Passkeys
12
+ # This module contains all the controller-level logic for:
13
+ #
14
+ # - User (resource) registration management (signup/delete account) using passkeys
15
+ # - User (resource) management of their passkeys
16
+ # - User (resource) authentication & reauthenticating using their passkeys
17
+ #
18
+ # Rather than having base classes, `Devise::Passkeys::Controllers` has a series of concerns
19
+ # that can be mixed into your app's controllers. This allows you to change behavior,
20
+ # and does not keep you stuck down a path that could be incompatible with your
21
+ # existing authentication setup.
22
+ #
23
+ # @example
24
+ # class Users::RegistrationsController < Devise::RegistrationsController
25
+ # include Devise::Passkeys::Controllers::RegistrationsControllerConcern
26
+ # end
27
+ #
28
+ #
29
+ # class Users::SessionsController < Devise::SessionsController
30
+ # include Devise::Passkeys::Controllers::SessionsControllerConcern
31
+ # # ... any custom code you need
32
+ #
33
+ # def relying_party
34
+ # WebAuthn::RelyingParty.new(...)
35
+ # end
36
+ # end
37
+ #
38
+ # # frozen_string_literal: true
39
+ #
40
+ # class Users::ReauthenticationController < DeviseController
41
+ # include Devise::Passkeys::Controllers::ReauthenticationControllerConcern
42
+ # # ... any custom code you need
43
+ #
44
+ # def relying_party
45
+ # WebAuthn::RelyingParty.new(...)
46
+ # end
47
+ # end
48
+ #
49
+ # # frozen_string_literal: true
50
+ #
51
+ # class Users::PasskeysController < DeviseController
52
+ # include Devise::Passkeys::Controllers::PasskeysControllerConcern
53
+ # # ... any custom code you need
54
+ #
55
+ # def relying_party
56
+ # WebAuthn::RelyingParty.new(...)
57
+ # end
58
+ # end
59
+ #
60
+ # *Note:* The `Devise::Passkeys::Controllers::Concerns` namespace is for:
61
+ # > Code, related to the concerns for controllers, that can be extracted into a standalone
62
+ # > module that can be included & extended as needed for apps that need
63
+ # > to do something custom with their setup.
64
+ # >
65
+ # > https://github.com/ruby-passkeys/devise-passkeys/issues/4#issuecomment-1590357907
12
66
  module Controllers
13
67
  end
14
68
  end
@@ -2,8 +2,16 @@
2
2
 
3
3
  module Devise
4
4
  module Models
5
+ # This is the actual module that gets included in your
6
+ # model when you include `:passkey_authenticatable` in the
7
+ # `devise` call (eg: `devise :passkey_authenticatable, ...`).
5
8
  module PasskeyAuthenticatable
6
- def after_passkey_authentication; end
9
+ # This is a callback that is called right after a successful passkey authentication.
10
+ #
11
+ # By default, it is a no-op, but you can override it in your model for any custom behavior
12
+ # (such as notifying the user of a new login).
13
+ # @param passkey [String] the passkey that was used for authentication
14
+ def after_passkey_authentication(passkey:); end
7
15
  end
8
16
  end
9
17
  end
@@ -35,8 +35,6 @@ module Devise
35
35
 
36
36
  private
37
37
 
38
- attr_accessor :maximum_passkeys_per_user
39
-
40
38
  def passkey_class(resource)
41
39
  if resource.respond_to?(:association) # ActiveRecord
42
40
  resource.association(:passkeys).klass
@@ -9,6 +9,13 @@ module Devise
9
9
  def authentication_challenge_key
10
10
  "#{mapping.singular}_current_reauthentication_challenge"
11
11
  end
12
+
13
+ # Reauthentication runs through Authentication (user_set)
14
+ # as part of its cycle, which would normally reset CSRF
15
+ # data in the session
16
+ def clean_up_csrf?
17
+ false
18
+ end
12
19
  end
13
20
  end
14
21
  end
@@ -32,7 +32,7 @@ module Devise
32
32
 
33
33
  if validate(resource)
34
34
  remember_me(resource)
35
- resource.after_passkey_authentication
35
+ resource.after_passkey_authentication(passkey: passkey)
36
36
  record_passkey_use(passkey: passkey)
37
37
  success!(resource)
38
38
  return
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Devise
4
4
  module Passkeys
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
@@ -11,7 +11,29 @@ require_relative "passkeys/reauthentication_strategy"
11
11
  require_relative "passkeys/version"
12
12
 
13
13
  module Devise
14
+ # This module provides a devise extension to use passkeys instead
15
+ # of passwords for user authentication.
16
+ #
17
+ # It is lightweight and non-configurable. It does what it has to do and
18
+ # leaves some manual implementation to you.
19
+ #
20
+ # Please consult the {file:README.md#label-Usage} for installation & configuration instructions;
21
+ # and the links below for additional reading about:
22
+ #
23
+ # - What passkeys are
24
+ # - The underlying gems used to build this devise extension
25
+ # - Platform support & user interface implementation guides
26
+ #
27
+ # @see https://webauthn.guide
28
+ # @see https://passkeys.dev
29
+ # @see https://fidoalliance.org/passkeys
30
+ # @see https://github.com/cedarcode/webauthn-ruby
31
+ # @see https://github.com/ruby-passkeys/warden-webauthn
14
32
  module Passkeys
33
+ # This is a helper method that creates and returns a passkey for
34
+ # the given user (`resource`), using the provided label & `WebAuthn::Credential`
35
+ # @see PasskeyIssuer#create_and_return_passkey
36
+ # @return A saved passkey for the the given user (`resource`)
15
37
  def self.create_and_return_passkey(resource:, label:, webauthn_credential:, extra_attributes: {})
16
38
  PasskeyIssuer.build.create_and_return_passkey(
17
39
  resource: resource,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise-passkeys
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Cannon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-07 00:00:00.000000000 Z
11
+ date: 2023-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: devise
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 4.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
- version: '0'
26
+ version: 4.7.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: warden-webauthn
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.2.0
33
+ version: 0.2.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.2.0
40
+ version: 0.2.1
41
41
  description: A Devise extension to use passkeys instead of passwords for authentication,
42
42
  using warden-webauthn
43
43
  email:
@@ -47,21 +47,24 @@ extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
49
  - ".rubocop.yml"
50
+ - ".yardopts"
50
51
  - Appraisals
51
52
  - CHANGELOG.md
52
53
  - CODE_OF_CONDUCT.md
54
+ - CONTRIBUTING.md
53
55
  - Gemfile
54
56
  - Gemfile.lock
55
57
  - LICENSE.txt
56
58
  - README.md
57
59
  - Rakefile
60
+ - THANKS.md
58
61
  - devise-passkeys.gemspec
59
62
  - gemfiles/.bundle/config
60
63
  - gemfiles/rails_6.gemfile
61
64
  - gemfiles/rails_7.gemfile
62
65
  - lib/devise/passkeys.rb
63
66
  - lib/devise/passkeys/controllers.rb
64
- - lib/devise/passkeys/controllers/concerns/passkey_reauthentication.rb
67
+ - lib/devise/passkeys/controllers/concerns/reauthentication.rb
65
68
  - lib/devise/passkeys/controllers/concerns/reauthentication_challenge.rb
66
69
  - lib/devise/passkeys/controllers/passkeys_controller_concern.rb
67
70
  - lib/devise/passkeys/controllers/reauthentication_controller_concern.rb