passkeys-rails 0.3.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afbb635c3ddfd36d60bccbf936e2a67e091a6bb15822683c9c1db050cdd49909
4
- data.tar.gz: c9ef1cf6d9e9f5a760037efb831b856dbf706c0860fbf945eadd616c37cb297d
3
+ metadata.gz: 8aeb76eb5817dbc1b1fac8a6205b5154772bd04d91f45596952b9b10e319f997
4
+ data.tar.gz: 0f3eb68558500c17ea980a1a1e0b00db8ddf13dfead9ef8568fb8a8d295f96ae
5
5
  SHA512:
6
- metadata.gz: 92e7f2a72715c7c4b313d57f7dc1c928cf334375fcdd28fc104f86721562b45484220234e8e5924106fce344e94d95f9cb7e29d0d6879e4ac73451e7a1a17915
7
- data.tar.gz: 686d6a95cec8274eaadd3fa1555a89f0e1554bc248c1f30eca1ac253933a158e8d12e08bcd74e53b42cbe33a9e0a1630ed14d1ce3a7205a2fe289366d3cbe2c3
6
+ metadata.gz: 2f136f27de81f280d9d8e55e96b2f7c4729ded92a7b9c0339f0c766d0b8604732de430dd5f6e082ed700dca9422cc3c1af975dfae74aa267757d955b3bc15733
7
+ data.tar.gz: 92587364bdb4f41aa35dfaeef432bab42e77d6dd4a8e49b6797b12bd2a42f4ef0ecd9ed6dca5575abf3e068c0005c998d863f3eb7b1443eb4d01ac2271f73205
data/CHANGELOG.md CHANGED
@@ -1,53 +1,65 @@
1
- ### 0.3.0
1
+ ### 0.3.2 (2024/10/01)
2
2
 
3
- * Added debug_register endpoint.
4
- * Fixed authenticatable_params for register enpoint.
5
- * Added notifications to certain controller actions.
6
- * Improved spec error helper.
3
+ - Changed from unsigned cookies to short lived signed cookies
4
+ - Added RELEASING.md
7
5
 
8
- ### 0.2.1
6
+ ### 0.3.1 (2023/11/30)
7
+
8
+ - Fixed a bug in reading session/cookie variables
9
+ - Added webauthn configuration parameters to this gem's configuration
10
+ - Moved configuration to its own class
11
+ - Added more info to the README
12
+
13
+ ### 0.3.0 (2023/08/01)
14
+
15
+ - Added debug_register endpoint.
16
+ - Fixed authenticatable_params for register enpoint.
17
+ - Added notifications to certain controller actions.
18
+ - Improved spec error helper.
19
+
20
+ ### 0.2.1 (2023/07/29)
9
21
 
10
22
  Added ability to pass either the auth token string or a request with one in the header to authenticate methods.
11
23
 
12
- ### 0.2.0
24
+ ### 0.2.0 (2023/07/28)
13
25
 
14
- * Added passkeys/debug_login functionality.
26
+ - Added passkeys/debug_login functionality.
15
27
 
16
- ### 0.1.7
28
+ ### 0.1.7 (2023/07/26)
17
29
 
18
- * Added IntegrationHelpers to support client testing.
19
- * Updated methods for interfacing with Rails client app.
20
- * Changed route path added by the generator.
30
+ - Added IntegrationHelpers to support client testing.
31
+ - Updated methods for interfacing with Rails client app.
32
+ - Changed route path added by the generator.
21
33
 
22
- ### 0.1.6
34
+ ### 0.1.6 (2023/07/26)
23
35
 
24
- * Added default_class and class_whitelist config parameters.
36
+ - Added default_class and class_whitelist config parameters.
25
37
 
26
- ### 0.1.5
38
+ ### 0.1.5 (2023/07/24)
27
39
 
28
- * Updated validation to ensure the agent has completed registration to be considered valid.
40
+ - Updated validation to ensure the agent has completed registration to be considered valid.
29
41
 
30
- ### 0.1.4
42
+ ### 0.1.4 (2023/07/23)
31
43
 
32
- * Changed namespace from Passkeys::Rails to PasskeysRails
44
+ - Changed namespace from Passkeys::Rails to PasskeysRails
33
45
 
34
- ### 0.1.3
46
+ ### 0.1.3 (2023/07/23)
35
47
 
36
- * More restructuring and fixed issue where autoloading failed
48
+ - More restructuring and fixed issue where autoloading failed
37
49
  during client app initialization.
38
50
 
39
- ### 0.1.2
51
+ ### 0.1.2 (2023/07/23)
40
52
 
41
- * Restructured lib directory.
53
+ - Restructured lib directory.
42
54
 
43
- * Fixed naming convention for gem/gemspec.
55
+ - Fixed naming convention for gem/gemspec.
44
56
 
45
- * Fixed exception handling.
57
+ - Fixed exception handling.
46
58
 
47
- ### 0.1.1
59
+ ### 0.1.1 (2023/07/23)
48
60
 
49
- * Fixed dependency
61
+ - Fixed dependency
50
62
 
51
- ### 0.1.0
63
+ ### 0.1.0 (2023/07/23)
52
64
 
53
- * Initial release - looking for feedback
65
+ - Initial release - looking for feedback
data/README.md CHANGED
@@ -1,42 +1,60 @@
1
+ # PasskeysRails - easy to integrate back end for implementing mobile passkeys
2
+
1
3
  [![Gem Version](https://badge.fury.io/rb/passkeys-rails.svg?cachebust=0.2.1)](https://badge.fury.io/rb/passkeys-rails)
2
4
  [![Build Status](https://app.travis-ci.com/alliedcode/passkeys-rails.svg?branch=main)](https://travis-ci.org/alliedcode/passkeys-rails)
3
5
  [![codecov](https://codecov.io/gh/alliedcode/passkeys-rails/branch/main/graph/badge.svg?token=UHSNJDUL21)](https://codecov.io/gh/alliedcode/passkeys-rails)
4
6
 
5
- # PasskeysRails
7
+ <p align="center" >
8
+ Created by <b>Troy Anderson, Allied Code</b> - <a href="https://alliedcode.com">alliedcode.com</a>
9
+ </p>
6
10
 
7
- Devise is awesome, but we don't need all that UI/UX for PassKeys, especially for an API back end.
11
+ PasskeysRails is a gem you can add to a Rails app to enable passskey registration and authorization from mobile front ends. PasskeysRails leverages webauthn for the cryptographic work, and presents a simple API interface for passkey registration, authentication, and testing.
8
12
 
9
13
  The purpose of this gem is to make it easy to provide a rails back end API that supports PassKey authentication. It uses the [`webauthn`](https://github.com/w3c/webauthn) gem to do the cryptographic work and presents a simple API interface for passkey registration and authentication.
10
14
 
11
15
  The target use case for this gem is a mobile application that uses a rails based API service to manage resources. The goal is to make it simple to register and authenticate users using passkeys from mobile applications in a rails API service.
12
16
 
17
+ What about [devise](https://github.com/heartcombo/devise)? Devise is awesome, but we don't need all that UI/UX for PassKeys, especially for an API back end.
18
+
19
+ ## Documentation
20
+ * [Usage](#usage)
21
+ * [Installation](#installation)
22
+ * [Rails Integration - Standard](#rails-Integration-standard)
23
+ * [Rails Integration - Grape](#rails-Integration-grape)
24
+ * [Notifications](#notifications)
25
+ * [Failure Codes](#failure-codes)
26
+ * [Testing](#testing)
27
+ * [Mobile App Integration](#mobile-application-integration)
28
+ * [Reference/Example Mobile Applications](#referenceexample-mobile-applications)
13
29
 
14
30
  ## Usage
15
31
 
16
- **PasskeysRails** maintains an `Agent` model and related `Passkeys`. If you have a user model, add `include PasskeysRails::Authenticatable` to your model and include the name of that class (e.g. `"User"`) in the `authenticatable_class` param when calling the register API or set the `PasskeysRails.default_class` to the name of that class.
32
+ **PasskeysRails** maintains a `PasskeysRails::Agent` model and related `PasskeysRails::Passkeys`. In rails apps that maintain their own "user" model, add `include PasskeysRails::Authenticatable` to that model and include the name of that class (e.g. `"User"`) in the `authenticatable_class` param when calling the register API or set the `PasskeysRails.default_class` to the name of that class.
33
+
34
+ In mobile apps, leverage the platform specific Passkeys APIs for ***registration*** and ***authentication***, and call the **PasskeysRails** API endpoints to complete the ceremony. **PasskeysRails** provides endpoints to support ***registration***, ***authentication***, ***token refresh***, and ***debugging***.
17
35
 
18
36
  ### Optionally providing a **"user"** model during registration
19
37
 
20
- **PasskeysRails** does not require that you supply your own model, but it's often useful to do so. For example, if you have a User model that you would like to have created at registration, you can supply the model name in the `finishRegistration` API call.
38
+ **PasskeysRails** does not require any application specific models, but it's often useful to have one. For example, a User model can be created at registration. **PasskeysRails** provides two mechanisms to support this. Either provide the name of the model in the `authenticatable_class` param when calling the `finishRegistration` endpoint, or set a `default_class` in `config/initializers/passkeys_rails.rb`.
21
39
 
22
- **PasskeysRails** supports multiple `"user"` models. Whatever model name you supply will be created during a successful the `finishRegiration` API call. When created, it will be provided an opportunity to do any initialization at that time.
40
+ **PasskeysRails** supports multiple different application specific models. Whatever model name supplied when calling the `finishRegistration` endpoint will be created during a successful the `finishRegiration` process. When created, it will be provided an opportunity to do any initialization at that time.
23
41
 
24
- There are two **PasskeysRails** configuration options related to this: `default_class` and `class_whitelist` - see below.
42
+ There are two **PasskeysRails** configuration options related to this: `default_class` and `class_whitelist`:
25
43
 
26
44
  #### `default_class`
27
45
 
28
- Configure `default_class` in `passkeys_rails.rb`. Its value will be used during registration if none is provided in the API call. The default value is `"User"`. Since the `default_class` is just a default, it can be overridden in the `finishRegiration` API call to use a different model. If no model is to be used by default, set it to nil.
46
+ Configure `default_class` in `config/initializers/passkeys_rails.rb`. Its value will be used during registration if none is provided in the API call. The default value is `"User"`. Since the `default_class` is just a default, it can be overridden in the `finishRegiration` API call to use a different model. If no model is to be used by default, set it to nil.
29
47
 
30
48
  #### `class_whitelist`
31
49
 
32
- Configure `class_whitelist` in `passkeys_rails.rb`. The default value is `nil`. When `nil`, no whitelist will be applied. If it is non-nil, it should be an array of class names that are allowed during registration. Supply an empty array to prevent **PasskeysRails** from attempting to create anything other than its own `PasskeysRails::Agent` during registration.
50
+ Configure `class_whitelist` in `config/initializers/passkeys_rails.rb`. The default value is `nil`. When `nil`, no whitelist will be applied. If it is non-nil, it should be an array of class names that are allowed during registration. Supply an empty array to prevent **PasskeysRails** from attempting to create anything other than its own `PasskeysRails::Agent` during registration.
33
51
 
34
52
  ## Installation
35
53
 
36
54
  Add this line to your application's Gemfile:
37
55
 
38
56
  ```ruby
39
- gem "passkeys_rails"
57
+ gem "passkeys-rails"
40
58
  ```
41
59
 
42
60
  And then execute:
@@ -58,29 +76,32 @@ $ rails generate passkeys_rails:install
58
76
 
59
77
  This will add the `config/initializers/passkeys_rails.rb` configuration file, passkeys routes, and a couple of database migrations to your project.
60
78
 
61
- ### Adding to an standard rails project
62
79
 
63
- 1. Add `before_action :authenticate_passkey!`
80
+ <a id="rails-Integration-standard"></a>
81
+ ## Rails Integration <p><small>Adding to a standard rails project</small></p>
64
82
 
65
- To prevent access to controller actions, add `before_action :authenticate_passkey!`. If an action is attempted without an authenticated entity, an error will be rendered in JSON with an :unauthorized result code.
83
+ - ### Add `before_action :authenticate_passkey!`
66
84
 
67
- 1. Use `current_agent` and `current_agent.authenticatable`
85
+ To prevent access to controller actions, add `before_action :authenticate_passkey!`. If an action is attempted without an authenticated entity, an error will be rendered in JSON with an :unauthorized result code.
68
86
 
69
- To access the currently authenticated entity, use `current_agent`. If you associated the registration of the agent with one of your own models, use `current_agent.authenticatable`. For example, if you associated the `User` class with the registration, `current_agent.authenticatable` will be a User object.
87
+ - ### Use `current_agent` and `current_agent.authenticatable`
70
88
 
71
- 1. Add `include PasskeysRails::Authenticatable` to model class(es)
89
+ To access the currently authenticated entity, use `current_agent`. If you associated the registration of the agent with one of your own models, use `current_agent.authenticatable`. For example, if you associated the `User` class with the registration, `current_agent.authenticatable` will be a User object.
90
+
91
+ - ### Add `include PasskeysRails::Authenticatable` to model class(es)
72
92
 
73
93
  If you have one or more classes that you want to use with authentication - e.g. a User class and an AdminUser class - add `include PasskeysRails::Authenticatable` to each of those classes. That adds a `registered?` method that you can call on your model to determine if they are registerd with your service, and a `registering_with(params)` method that you can override to initialize attributes of your model when it is created during registration. `params` is a hash with params passed to the API when registering. When called, your object has been built, but not yet saved. Upon return, **PasskeysRails** will attempt to save your object before finishing registration. If it is not valid, the registration will fail as well, returning the error error details to the caller.
74
94
 
75
- ### Adding to a Grape API rails project
95
+ <a id="rails-Integration-grape"></a>
96
+ ## Rails Integration - <p><small>Adding to a Grape API rails project</small></p>
76
97
 
77
- 1. Call `PasskeysRails.authenticate(request)` to authenticate the request.
98
+ - ### Call `PasskeysRails.authenticate(request)` to authenticate the request.
78
99
 
79
100
  Call `PasskeysRails.authenticate(request)` to get an object back that responds to `.success?` and `.failure?` as well as `.agent`, `.code`, and `.message`.
80
101
 
81
102
  Alternatively, call `PasskeysRails.authenticate!(request)` from a helper in your base class. It will raise a `PasskeysRails.Error` exception if the caller isn't authenticated. You can catch the exception and render an appropriate error. The exception contains the error code and message.
82
103
 
83
- 1. Consider adding the following helpers to your base API class:
104
+ - ### Consider adding the following helpers to your base API class:
84
105
 
85
106
  ```ruby
86
107
  helpers do
@@ -109,15 +130,17 @@ This will add the `config/initializers/passkeys_rails.rb` configuration file, pa
109
130
 
110
131
  To prevent access to various endpoints, add `before_action :authenticate_passkey!` or call `authenticate_passkey!` from any method that requires authentication. If an action is attempted without an authenticated entity, an error will be rendered in JSON with an :unauthorized result code.
111
132
 
112
- 1. Use `current_agent` and `current_agent.authenticatable`
133
+ - ### Use `current_agent` and `current_agent.authenticatable`
113
134
 
114
135
  To access the currently authenticated entity, use `current_agent`. If you associated the registration of the agent with one of your own models, use `current_agent.authenticatable`. For example, if you associated the `User` class with the registration, `current_agent.authenticatable` will be a User object.
115
136
 
116
- ### Notifications
137
+ ## Notifications
138
+
139
+ Certain actions trigger notifications that can be subscribed. See `subscribe` in `config/initializers/passkeys_rails.rb`.
117
140
 
118
- Certain actions trigger notifications that can be subscribed. See `subscribe` in `passkeys_rails.rb`.
141
+ These are completely optional. **PasskeysRails** will manage all the credentials and keys without these being implemented. They are useful for taking application specific actions like logging based on the authentication related events.
119
142
 
120
- #### Events
143
+ ### Events
121
144
 
122
145
  - `:did_register ` - a new agent has registered
123
146
 
@@ -125,7 +148,7 @@ Certain actions trigger notifications that can be subscribed. See `subscribe` i
125
148
 
126
149
  - `:did_refresh` - an agent's auth token has been refreshed
127
150
 
128
- A convenient place to set these up in is in `passkeys_rails.rb`
151
+ A convenient place to set these up in is in `config/initializers/passkeys_rails.rb`
129
152
 
130
153
  ```ruby
131
154
  PasskeysRails.config do |c|
@@ -147,10 +170,9 @@ PasskeysRails.subscribe(:did_register) do |event, agent, request|
147
170
  end
148
171
  ```
149
172
 
173
+ ## Failure Codes
150
174
 
151
- ### Authentication Failure
152
-
153
- 1. In the event of authentication failure, PasskeysRails returns an error code and message.
175
+ 1. In the event of authentication failure, **PasskeysRails** API endpoints render an error code and message.
154
176
 
155
177
  1. In a standard rails controller, the error code and message are rendered in JSON if `before_action :authenticate_passkey!` fails.
156
178
 
@@ -166,14 +188,12 @@ end
166
188
  - When `.code` is `:expired_token`, `.message` is **The token has expired**, which means that the token is valid, but expired, thuis it's not considered authentic.
167
189
  - When `.code` is `:token_error`, `.message` is a description of the error. This is a catch-all in the event we are unable to decode the token.
168
190
 
169
- In the future, the intention is to have the `.code` value stay consistent even if the `.message` changes. This also allows you to localize the messages as need using the code.
191
+ In the future, the intention is to have the `.code` value stay consistent even if the `.message` changes. This also allows you to localize the messages as needed using the code.
170
192
 
171
- ### Test Helpers
193
+ ## Testing
172
194
 
173
195
  PasskeysRails includes some test helpers for integration tests. In order to use them, you need to include the module in your test cases/specs.
174
196
 
175
- ### Integration tests
176
-
177
197
  Integration test helpers are available by including the `PasskeysRails::IntegrationHelpers` module.
178
198
 
179
199
  ```ruby
@@ -210,20 +230,38 @@ RSpec.describe 'Posts', type: :request do
210
230
  end
211
231
  ```
212
232
 
213
- ### Mobile Application Integration
233
+ ## Mobile Application Integration
234
+
235
+ ### Prerequisites
236
+
237
+ For iOS, you need to associate your app with your server. This amounts to setting up a special file on your server that defines the association. See [setup your apple-app-site-association](#Ensure-`.well-known/apple-app-site-association`-is-in-place)
214
238
 
215
- There are n groups of API endpoints that your mobile application may consume.
239
+
240
+ ### Mobile API Endpoints
241
+
242
+ There are 3 groups of API endpoints that your mobile application might consume.
216
243
 
217
244
  1. Unauthenticated (public) endpoints
218
245
  1. Authenticated (private) endpoints
219
- 1. Passey endpoints (for supporting authentication)
246
+ 1. Passkey endpoints (for supporting authentication)
220
247
 
221
- **Unauthenticated endpoints** can be consumed without and authentication.
248
+ **Unauthenticated endpoints** can be consumed without any authentication.
222
249
 
223
250
  **Authenticated endpoints** are protected by `authenticate_passkey!` or `PasskeysRails.authenticate!(request)`. Those methods check for and validate the `X-Auth` header, which must be set to the auth token returned in the `AuthResponse`, described below.
224
251
 
225
252
  **Passkey endpoints** are supplied by this gem and allow you to register a user, authenticate (login) a user, and refresh the token. This section describes these endpoints.
226
253
 
254
+ This gem supports the Passkey endpoints.
255
+
256
+ ### Passkey Endpoints
257
+
258
+ * [POST /passkeys/challenge](post-passkeys-challenge)
259
+ * [POST /passkeys/register](post-passkeys-register)
260
+ * [POST /passkeys/authenticate](post-passkeys-authenticate)
261
+ * [POST /passkeys/refresh](post-passkeys-refresh)
262
+ * [POST /passkeys/debug_register](post-passkeys-debug-register)
263
+ * [POST /passkeys/debug_login](post-passkeys-debug-login)
264
+
227
265
  All Passkey endpoints accept and respond with JSON.
228
266
 
229
267
  On **success**, they will respond with a 200 or 201 response code and relevant JSON.
@@ -249,18 +287,24 @@ Some endpoints return an `AuthResponse`, which has this JSON structure:
249
287
  }
250
288
  ```
251
289
 
252
- #### POST /passkeys/challenge
290
+ ### POST /passkeys/challenge
253
291
 
254
292
  Submit this to begin registration or authentication.
255
293
 
256
- Supply a `{ "username": "unique username" } ` to register a new credential.
294
+ #### Registration (register)
295
+
296
+ To begin registration of a new credential, supply a `{ "username": "unique username" }`.
257
297
  If all goes well, the JSON response will be the `options_for_create` from webauthn.
258
298
  If the username is already in use, or anything else goes wrong, an error with code `validation_errors` will be returned.
259
299
 
260
- Omit the `username` when authenticating (logging in).
261
- The JSON response will be the `options_for_get` from webauthn.
300
+ After receiving a successful response, follow up with a POST to `/passkeys/register`, below.
301
+
302
+ #### Authentication (login)
303
+ To begin authenticating an existing credential, omit the `username`. The JSON response will be the `options_for_get` from webauthn.
262
304
 
263
- #### POST /passkeys/register
305
+ After receiving a successful response, follow up with a POST to `/passkeys/authenticate`, below.
306
+
307
+ ### POST /passkeys/register
264
308
 
265
309
  After calling the `challenge` endpoint with a `username`, and handling its response, finish registering by calling this endpoint.
266
310
 
@@ -291,16 +335,16 @@ On **success**, the response is an `AuthResponse`.
291
335
 
292
336
  Possible **failure codes** (using the `ErrorResponse` structure) are:
293
337
 
294
- - webauthn_error - something is wrong with the credential
295
- - error - something else went wrong during credentail validation - see the `message` in the `ErrorResponse`
296
- - passkey_error - unable to persiste the passkey
297
- - invalid_authenticatable_class - the supplied authenticatable class can't be created/found (check spelling & capitalization)
298
- - invalid_class_whitelist - the whitelist in the passkeys_rails.rb configuration is invalid - be sure it's nil or an array
299
- - invalid_authenticatable_class - the supplied authenticatable class is not allowed - maybe it's not in the whitelist
300
- - record_invalid - the object of the supplied authenticatable class cannot be saved due to validation errors
301
- - agent_not_found - the agent referenced in the credential cannot be found in the database
338
+ - `webauthn_error` - something is wrong with the credential
339
+ - `error` - something else went wrong during credentail validation - see the `message` in the `ErrorResponse`
340
+ - `passkey_error` - unable to persist the passkey
341
+ - `invalid_authenticatable_class` - the supplied authenticatable class can't be created/found (check spelling & capitalization)
342
+ - `invalid_class_whitelist` - the whitelist in the passkeys_rails.rb configuration is invalid - be sure it's nil or an array
343
+ - `invalid_authenticatable_class` - the supplied authenticatable class is not allowed - maybe it's not in the whitelist
344
+ - `record_invalid` - the object of the supplied authenticatable class cannot be saved due to validation errors
345
+ - `agent_not_found` - the agent referenced in the credential cannot be found in the database
302
346
 
303
- #### POST /passkeys/authenticate
347
+ ### POST /passkeys/authenticate
304
348
 
305
349
  After calling the `challenge` endpoint without a `username`, and handling its response, finish authenticating by calling this endpoint.
306
350
 
@@ -325,12 +369,12 @@ On **success**, the response is an `AuthResponse`.
325
369
 
326
370
  Possible **failure codes** (using the `ErrorResponse` structure) are:
327
371
 
328
- - webauthn_error - something is wrong with the credential
329
- - passkey_not_found - the passkey referenced in the credential cannot be found in the database
372
+ - `webauthn_error` - something is wrong with the credential
373
+ - `passkey_not_found` - the passkey referenced in the credential cannot be found in the database
330
374
 
331
- #### POST /passkeys/refresh
375
+ ### POST /passkeys/refresh
332
376
 
333
- The token will expire after some time (configurable in passkeys_rails.rb). Before that happens, refresh it using this API. Once it's expired, to get a new token, use the /authentication API.
377
+ The token will expire after some time (configurable in `config/initializers/passkeys_rails.rb`). Before that happens, refresh it using this API. Once it expires, to get a new token, use the `/authentication` API.
334
378
 
335
379
  Supply the following JSON structure:
336
380
 
@@ -345,27 +389,27 @@ On **success**, the response is an `AuthResponse` with a new, refreshed token.
345
389
 
346
390
  Possible **failure codes** (using the `ErrorResponse` structure) are:
347
391
 
348
- - invalid_token - the token data is invalid
349
- - expired_token - the token is expired
350
- - token_error - some other error ocurred when decoding the token
392
+ - `invalid_token` - the token data is invalid
393
+ - `expired_token` - the token is expired
394
+ - `token_error` - some other error ocurred when decoding the token
351
395
 
352
- #### POST /passkeys/debug_login
396
+ ### POST /passkeys/debug_register
353
397
 
354
- As it may not be possible to acess Passkey functionality in mobile simulators, this endpoint may be called to login (authenticate) a username while bypassing the normal challenge/response sequence.
398
+ As it may not be possible to acess Passkey functionality in mobile simulators, this endpoint may be called to register a username while bypassing the normal challenge/response sequence.
355
399
 
356
- This endpoint only responds if DEBUG_LOGIN_REGEX is set in the server environment. It is very insecure to set this variable in a production environment as it bypasses all Passkey checks. It is only intended to be used during mobile application development.
400
+ This endpoint only responds if `DEBUG_LOGIN_REGEX` is set in the server environment. It is **very insecure to set this variable in a production environment** as it bypasses all Passkey checks. It is only intended to be used during mobile application development.
357
401
 
358
402
  To use this endpoint:
359
403
 
360
- 1. Manually create one or more PasskeysRails::Agent records in the database. A unique username is required for each.
404
+ 1. Set `DEBUG_LOGIN_REGEX` to a regex that matches any username you want to use during development - for example `^test(-\d+)?$` will match `test`, `test-1`, `test-123`, etc.
361
405
 
362
- 1. Set DEBUG_LOGIN_REGEX to a regex that matches any username you want to use during development - for example `^test(-\d+)?$` will match `test`, `test-1`, `test-123`, etc.
406
+ 1. In the mobile application, call this endpoint in stead of the `/passkeys/challenge` and `/passkeys/register`. The response is identicial to that of `/passkeys/register`.
363
407
 
364
- 1. In the mobile application, call this endpoint in stead of the /passkeys/challenge and /passkeys/authenticate. The response is identicial to that of /passkeys/authenticate.
408
+ 1. Use the response as if it was from `/passkeys/register`.
365
409
 
366
- 1. Use the response as if it was from /passkeys/authenticate.
410
+ If you supply a username that doesn't match the `DEBUG_LOGIN_REGEX`, the endpoint will respond with an error.
367
411
 
368
- If you supply a username that doesn't match the DEBUG_LOGIN_REGEX, the endpoint will respond with an error.
412
+ Supply the following JSON structure:
369
413
 
370
414
  ```JSON
371
415
  # POST body
@@ -377,71 +421,62 @@ On **success**, the response is an `AuthResponse`.
377
421
 
378
422
  Possible **failure codes** (using the `ErrorResponse` structure) are:
379
423
 
380
- - not_allowed - Invalid username (the username doesn't match the regex)
381
- - agent_not_found - No agent found with that username
382
-
383
- ## Reference/Example Mobile Applications
384
-
385
- **TODO**: Point to the soon-to-be-created reference mobile applications for how to use **passkeys-rails** for passkey authentication.
386
-
387
- ## Contributing
424
+ - `not_allowed` - Invalid username (the username doesn't match the regex)
425
+ - `invalid_authenticatable_class` - the supplied authenticatable class can't be created/found (check spelling & capitalization)
426
+ - `invalid_class_whitelist` - the whitelist in the passkeys_rails.rb configuration is invalid - be sure it's nil or an array
427
+ - `invalid_authenticatable_class` - the supplied authenticatable class is not allowed - maybe it's not in the whitelist
428
+ - `record_invalid` - the object of the supplied authenticatable class cannot be saved due to validation errors
388
429
 
389
- ### Contributing Guidelines
430
+ ### POST /passkeys/debug_login
390
431
 
391
- Thank you for considering contributing to PasskeysRails! We welcome your help to improve and enhance this project. Whether it's a bug fix, documentation update, or a new feature, your contributions are valuable to the community.
392
-
393
- To ensure a smooth collaboration, please follow the guidelines below when submitting your contributions:
394
-
395
- #### Code of Conduct
396
-
397
- Please note that this project follows the [Code of Conduct](https://github.com/alliedcode/passkeys-rails/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. If you encounter any behavior that violates the code, please report it to the project maintainers.
398
-
399
- #### How to Contribute
400
-
401
- 1. Fork the repository on GitHub.
402
-
403
- 2. Create a new branch for your contribution. Use a descriptive name that reflects the purpose of your changes.
404
-
405
- 3. Make your changes and commit them with clear and concise messages. Remember to follow the project's coding style and guidelines.
432
+ As it may not be possible to acess Passkey functionality in mobile simulators, this endpoint may be called to login (authenticate) a username while bypassing the normal challenge/response sequence.
406
433
 
407
- 4. Before submitting a pull request, ensure that your changes pass all existing tests and add relevant tests if applicable.
434
+ This endpoint only responds if `DEBUG_LOGIN_REGEX` is set in the server environment. It is **very insecure to set this variable in a production environment** as it bypasses all Passkey checks. It is only intended to be used during mobile application development.
408
435
 
409
- 5. Update the documentation if your changes introduce new features, modify existing behavior, or require user instructions.
436
+ To use this endpoint:
410
437
 
411
- 6. Squash your commits into a single logical commit if needed. Keep your commit history clean and focused.
438
+ 1. Manually create one or more PasskeysRails::Agent records in the database. A unique username is required for each.
412
439
 
413
- 7. Submit a pull request against the `main` branch of the original repository.
440
+ 1. Set `DEBUG_LOGIN_REGEX` to a regex that matches any username you want to use during development - for example `^test(-\d+)?$` will match `test`, `test-1`, `test-123`, etc.
414
441
 
415
- 8. Add a comment at the top of the CHANGELOG.md describing the change.
442
+ 1. In the mobile application, call this endpoint in stead of the `/passkeys/challenge` and `/passkeys/authenticate`. The response is identicial to that of `/passkeys/authenticate`.
416
443
 
417
- #### Pull Request Guidelines
444
+ 1. Use the response as if it was from `/passkeys/authenticate`.
418
445
 
419
- When submitting a pull request, please include the following details:
446
+ If you supply a username that doesn't match the `DEBUG_LOGIN_REGEX`, the endpoint will respond with an error.
420
447
 
421
- - A clear description of the changes you made and the problem it solves.
448
+ Supply the following JSON structure:
422
449
 
423
- - Any relevant issue numbers that your pull request addresses or fixes.
450
+ ```JSON
451
+ # POST body
452
+ {
453
+ "username": String
454
+ }
455
+ ```
456
+ On **success**, the response is an `AuthResponse`.
424
457
 
425
- - The steps to test your changes, so the project maintainers can verify them.
458
+ Possible **failure codes** (using the `ErrorResponse` structure) are:
426
459
 
427
- - Ensure that your pull request title and description are descriptive and informative.
460
+ - `not_allowed` - Invalid username (the username doesn't match the regex)
461
+ - `agent_not_found` - No agent found with that username
428
462
 
429
- #### Code Review Process
463
+ ## Reference/Example Mobile Applications
430
464
 
431
- All pull requests will undergo a code review process by the project maintainers. We appreciate your patience during this review process. Constructive feedback may be provided, and further changes might be requested.
465
+ There is a sample iOS app that integrates with **passkeys-rails** based server implementations. It's a great place to get a quick start on implementing passkyes in your iOS, iPadOS or MacOS apps.
432
466
 
433
- #### Contributor License Agreement
467
+ Check out the [PasskeysRailsDemo](https://github.com/alliedcode/PasskeysRailsDemo) app.
434
468
 
435
- By submitting a pull request, you acknowledge that your contributions will be licensed under the project's [MIT License](https://github.com/alliedcode/passkeys-rails/blob/main/MIT-LICENSE).
469
+ ## Contributing
436
470
 
437
- #### Reporting Issues
471
+ ### Contribution Guidelines
438
472
 
439
- If you encounter any bugs, problems, or have suggestions for improvement, please create an issue on the GitHub repository. Provide clear and detailed information about the issue to help us address it efficiently.
473
+ Thank you for considering contributing to PasskeysRails! We welcome your help to improve and enhance this project. Whether it's a bug fix, documentation update, or a new feature, your contributions are valuable to the community.
440
474
 
441
- #### Thank You
475
+ To ensure a smooth collaboration, please follow the [Contribution Guidelines](https://github.com/alliedcode/passkeys-rails/blob/main/CONTRIBUTION_GUIDELINES.md) when submitting your contributions.
442
476
 
443
- Your contributions are valuable, and we sincerely appreciate your efforts to improve PasskeysRails. Together, we can build a better software ecosystem for the community. Thank you for your support and happy contributing!
477
+ ### Code of Conduct
444
478
 
479
+ Please note that this project follows the [Code of Conduct](https://github.com/alliedcode/passkeys-rails/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. If you encounter any behavior that violates the code, please report it to the project maintainers.
445
480
 
446
481
  ## License
447
482
 
@@ -7,16 +7,23 @@ module PasskeysRails
7
7
  result = PasskeysRails::BeginChallenge.call!(username: challenge_params[:username])
8
8
 
9
9
  # Store the challenge so we can verify the future register or authentication request
10
- session[:passkeys_rails] = result.session_data
10
+ cookies.signed[:passkeys_rails] = {
11
+ value: result.cookie_data.to_json,
12
+ expire: Time.now.utc + (result.response.timeout / 1000),
13
+ secure: true,
14
+ httponly: true,
15
+ same_site: :strict
16
+ }
11
17
 
12
18
  render json: result.response.as_json
13
19
  end
14
20
 
15
21
  def register
22
+ cookie_data = JSON.parse(cookies.signed["passkeys_rails"] || "{}")
16
23
  result = PasskeysRails::FinishRegistration.call!(credential: attestation_credential_params.to_h,
17
24
  authenticatable_info: authenticatable_params&.to_h,
18
- username: session.dig(:passkeys_rails, :username),
19
- challenge: session.dig(:passkeys_rails, :challenge))
25
+ username: cookie_data["username"],
26
+ challenge: cookie_data["challenge"])
20
27
 
21
28
  broadcast(:did_register, agent: result.agent)
22
29
 
@@ -24,8 +31,9 @@ module PasskeysRails
24
31
  end
25
32
 
26
33
  def authenticate
34
+ cookie_data = JSON.parse(cookies.signed["passkeys_rails"] || "{}")
27
35
  result = PasskeysRails::FinishAuthentication.call!(credential: authentication_params.to_h,
28
- challenge: session.dig(:passkeys_rails, :challenge))
36
+ challenge: cookie_data["challenge"])
29
37
 
30
38
  broadcast(:did_authenticate, agent: result.agent)
31
39
 
@@ -10,7 +10,7 @@ module PasskeysRails
10
10
  options = result.options
11
11
 
12
12
  context.response = options
13
- context.session_data = session_data(options)
13
+ context.cookie_data = cookie_data(options)
14
14
  rescue Interactor::Failure => e
15
15
  context.fail! code: e.context.code, message: e.context.message
16
16
  end
@@ -25,7 +25,7 @@ module PasskeysRails
25
25
  end
26
26
  end
27
27
 
28
- def session_data(options)
28
+ def cookie_data(options)
29
29
  {
30
30
  username:,
31
31
  challenge: WebAuthn.standard_encoder.encode(options.challenge)
@@ -13,6 +13,8 @@ module PasskeysRails
13
13
  private
14
14
 
15
15
  def create_or_replace_unregistered_agent
16
+ context.fail! code: :origin_error, message: "config.wa_origin must be set" if WebAuthn.configuration.origin.blank?
17
+
16
18
  Agent.unregistered.where(username:).destroy_all
17
19
 
18
20
  agent = Agent.create(username:, webauthn_identifier: WebAuthn.generate_user_id)
@@ -28,7 +28,11 @@ module PasskeysRails
28
28
  rescue WebAuthn::Error => e
29
29
  context.fail!(code: :webauthn_error, message: e.message)
30
30
  rescue StandardError => e
31
- context.fail!(code: :error, message: e.message)
31
+ if e.message == "undefined method `end_with?' for nil:NilClass"
32
+ context.fail!(code: :webauthn_error, message: "origin is not set")
33
+ else
34
+ context.fail!(code: :error, message: e.message)
35
+ end
32
36
  end
33
37
 
34
38
  def store_passkey_and_register_agent!
@@ -51,7 +55,7 @@ module PasskeysRails
51
55
  def agent
52
56
  @agent ||= begin
53
57
  agent = Agent.find_by(username:)
54
- context.fail!(code: :agent_not_found, message: "Agent not found for session value: \"#{username}\"") if agent.blank?
58
+ context.fail!(code: :agent_not_found, message: "Agent not found for cookie value: \"#{username}\"") if agent.blank?
55
59
 
56
60
  agent
57
61
  end
@@ -60,4 +60,45 @@ PasskeysRails.config do |c|
60
60
  # c.subscribe(:did_register) do |event, agent, request|
61
61
  # puts("#{event} | #{agent.id} | #{request.headers}")
62
62
  # end
63
+
64
+ # PasskeysRails uses webauthn to help with the protocol.
65
+ # The following settings are passed throught webauthn.
66
+ # wa_origin is the only one requried
67
+
68
+ # This value needs to match `window.location.origin` evaluated by
69
+ # the User Agent during registration and authentication ceremonies.
70
+ # c.wa_origin = ENV['DEFAULT_HOST'] || https://myapp.mydomain.com
71
+
72
+ # Relying Party name for display purposes
73
+ # c.wa_relying_party_name = "My App Name"
74
+
75
+ # Optionally configure a client timeout hint, in milliseconds.
76
+ # This hint specifies how long the browser should wait for any
77
+ # interaction with the user.
78
+ # This hint may be overridden by the browser.
79
+ # https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout
80
+ # c.wa_credential_options_timeout = 120_000
81
+
82
+ # You can optionally specify a different Relying Party ID
83
+ # (https://www.w3.org/TR/webauthn/#relying-party-identifier)
84
+ # if it differs from the default one.
85
+ #
86
+ # In this case the default would be "auth.example.com", but you can set it to
87
+ # the suffix "example.com"
88
+ #
89
+ # c.wa_rp_id = "example.com"
90
+
91
+ # Configure preferred binary-to-text encoding scheme. This should match the encoding scheme
92
+ # used in your client-side (user agent) code before sending the credential to the server.
93
+ # Supported values: `:base64url` (default), `:base64` or `false` to disable all encoding.
94
+ #
95
+ # c.wa_encoding = :base64url
96
+
97
+ # Possible values: "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512", "RS1"
98
+ # Default: ["ES256", "PS256", "RS256"]
99
+ #
100
+ # c.wa_algorithms = ["ES256", "PS256", "RS256"]
101
+
102
+ # Append an algorithm to the existing set
103
+ # c.wa_algorithm = "PS512"
63
104
  end
@@ -1,49 +1,42 @@
1
1
  # rubocop:disable Naming/FileName
2
2
  require 'passkeys_rails/engine'
3
+ require 'passkeys_rails/configuration'
3
4
  require 'passkeys_rails/version'
4
5
  require_relative "generators/passkeys_rails/install_generator"
6
+ require 'forwardable'
5
7
 
6
8
  module PasskeysRails
7
9
  module Test
8
10
  autoload :IntegrationHelpers, 'passkeys_rails/test/integration_helpers'
9
11
  end
10
12
 
11
- # Secret used to encode the auth token.
12
- # Rails.application.secret_key_base is used if none is defined here.
13
- # Changing this value will invalidate all tokens that have been fetched
14
- # through the API.
15
- mattr_accessor(:auth_token_secret)
13
+ class << self
14
+ extend Forwardable
16
15
 
17
- # Algorithm used to generate the auth token.
18
- # Changing this value will invalidate all tokens that have been fetched
19
- # through the API.
20
- mattr_accessor :auth_token_algorithm, default: "HS256"
16
+ def_delegators :config, :auth_token_secret, :auth_token_algorithm, :auth_token_expires_in, :default_class, :class_whitelist
21
17
 
22
- # How long the auth token is valid before requiring a refresh or new login.
23
- # Set it to 0 for no expiration (not recommended in production).
24
- mattr_accessor :auth_token_expires_in, default: 30.days
18
+ def config
19
+ @config ||= begin
20
+ config = Configuration.new
21
+ yield(config) if block_given?
22
+ apply_webauthn_configuration(config)
25
23
 
26
- # Model to use when creating or authenticating a passkey.
27
- # This can be overridden when calling the API, but if no
28
- # value is supplied when calling the API, this value is used.
29
- # If nil, there is no default, and if none is supplied when
30
- # calling the API, no resource is created other than
31
- # a PaskeysRails::Agent that is used to track the passkey.
32
- #
33
- # This library doesn't assume that there will only be one
34
- # model, but it is a common use case, so setting the
35
- # default_class simplifies the use of the API in that case.
36
- mattr_accessor :default_class, default: "User"
24
+ config
25
+ end
26
+ end
27
+ end
37
28
 
38
- # By providing a class_whitelist, the API will require that
39
- # any supplied class is in the whitelist. If it is not, the
40
- # auth API will return an error. This prevents a caller from
41
- # attempting to create an unintended record on registration.
42
- # If nil, any model will be allowed.
43
- # If [], no model will be allowed.
44
- # This should be an array of symbols or strings,
45
- # for example: %w[User AdminUser]
46
- mattr_accessor :class_whitelist, default: nil
29
+ def self.apply_webauthn_configuration(config)
30
+ WebAuthn.configure do |c|
31
+ c.origin = config.wa_origin
32
+ c.rp_name = config.wa_relying_party_name if config.wa_relying_party_name
33
+ c.credential_options_timeout = config.wa_credential_options_timeout if config.wa_credential_options_timeout
34
+ c.rp_id = config.wa_rp_id if config.wa_rp_id
35
+ c.encoding = config.wa_encoding if config.wa_encoding
36
+ c.algorithms = config.wa_algorithms if config.wa_algorithms
37
+ c.algorithms << config.wa_algorithm if config.wa_algorithm
38
+ end
39
+ end
47
40
 
48
41
  # Convenience method to subscribe to various events in PasskeysRails.
49
42
  #
@@ -104,16 +97,6 @@ module PasskeysRails
104
97
  message: auth.message)
105
98
  end
106
99
 
107
- class << self
108
- def config
109
- yield self
110
- end
111
- end
112
-
113
100
  require 'passkeys_rails/railtie' if defined?(Rails)
114
101
  end
115
-
116
- ActiveSupport.on_load(:before_initialize) do
117
- PasskeysRails.auth_token_secret ||= Rails.application.secret_key_base
118
- end
119
102
  # rubocop:enable Naming/FileName
@@ -0,0 +1,62 @@
1
+ module PasskeysRails
2
+ class Configuration
3
+ # Secret used to encode the auth token.
4
+ # Rails.application.secret_key_base is used if none is defined here.
5
+ # Changing this value will invalidate all tokens that have been fetched
6
+ # through the API.
7
+ attr_accessor :auth_token_secret
8
+
9
+ # Algorithm used to generate the auth token.
10
+ # Changing this value will invalidate all tokens that have been fetched
11
+ # through the API.
12
+ attr_accessor :auth_token_algorithm
13
+
14
+ # How long the auth token is valid before requiring a refresh or new login.
15
+ # Set it to 0 for no expiration (not recommended in production).
16
+ attr_accessor :auth_token_expires_in
17
+
18
+ # Model to use when creating or authenticating a passkey.
19
+ # This can be overridden when calling the API, but if no
20
+ # value is supplied when calling the API, this value is used.
21
+ # If nil, there is no default, and if none is supplied when
22
+ # calling the API, no resource is created other than
23
+ # a PaskeysRails::Agent that is used to track the passkey.
24
+ #
25
+ # This library doesn't assume that there will only be one
26
+ # model, but it is a common use case, so setting the
27
+ # default_class simplifies the use of the API in that case.
28
+ attr_accessor :default_class
29
+
30
+ # By providing a class_whitelist, the API will require that
31
+ # any supplied class is in the whitelist. If it is not, the
32
+ # auth API will return an error. This prevents a caller from
33
+ # attempting to create an unintended record on registration.
34
+ # If nil, any model will be allowed.
35
+ # If [], no model will be allowed.
36
+ # This should be an array of symbols or strings,
37
+ # for example: %w[User AdminUser]
38
+ attr_accessor :class_whitelist
39
+
40
+ # webauthn settings
41
+ attr_accessor :wa_origin,
42
+ :wa_relying_party_name,
43
+ :wa_credential_options_timeout,
44
+ :wa_rp_id,
45
+ :wa_encoding,
46
+ :wa_algorithms,
47
+ :wa_algorithm
48
+
49
+ def initialize
50
+ # defaults
51
+ @auth_token_secret = Rails.application.secret_key_base
52
+ @auth_token_algorithm = "HS256"
53
+ @auth_token_expires_in = 30.days
54
+ @default_class = "User"
55
+ @wa_origin = "https://example.com"
56
+ end
57
+
58
+ def subscribe(event_name)
59
+ PasskeysRails.subscribe(event_name)
60
+ end
61
+ end
62
+ end
@@ -1,3 +1,3 @@
1
1
  module PasskeysRails
2
- VERSION = "0.3.0".freeze
2
+ VERSION = "0.3.2".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passkeys-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Troy Anderson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-01 00:00:00.000000000 Z
11
+ date: 2024-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '7.0'
19
+ version: '7.2'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 7.0.5
22
+ version: 7.2.1
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '7.0'
29
+ version: '7.2'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 7.0.5
32
+ version: 7.2.1
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: interactor
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -50,266 +50,280 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: 2.7.1
53
+ version: 2.9.1
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 2.7.1
60
+ version: 2.9.1
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: webauthn
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 3.0.0
67
+ version: 3.1.0
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 3.0.0
74
+ version: 3.1.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: cbor
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.5.9.8
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.5.9.8
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: dotenv
77
91
  requirement: !ruby/object:Gem::Requirement
78
92
  requirements:
79
93
  - - "~>"
80
94
  - !ruby/object:Gem::Version
81
- version: 2.8.1
95
+ version: 3.1.4
82
96
  type: :development
83
97
  prerelease: false
84
98
  version_requirements: !ruby/object:Gem::Requirement
85
99
  requirements:
86
100
  - - "~>"
87
101
  - !ruby/object:Gem::Version
88
- version: 2.8.1
102
+ version: 3.1.4
89
103
  - !ruby/object:Gem::Dependency
90
104
  name: puma
91
105
  requirement: !ruby/object:Gem::Requirement
92
106
  requirements:
93
107
  - - "~>"
94
108
  - !ruby/object:Gem::Version
95
- version: 5.6.5
109
+ version: 6.4.3
96
110
  type: :development
97
111
  prerelease: false
98
112
  version_requirements: !ruby/object:Gem::Requirement
99
113
  requirements:
100
114
  - - "~>"
101
115
  - !ruby/object:Gem::Version
102
- version: 5.6.5
116
+ version: 6.4.3
103
117
  - !ruby/object:Gem::Dependency
104
118
  name: rake
105
119
  requirement: !ruby/object:Gem::Requirement
106
120
  requirements:
107
121
  - - "~>"
108
122
  - !ruby/object:Gem::Version
109
- version: '13.0'
123
+ version: 13.2.1
110
124
  type: :development
111
125
  prerelease: false
112
126
  version_requirements: !ruby/object:Gem::Requirement
113
127
  requirements:
114
128
  - - "~>"
115
129
  - !ruby/object:Gem::Version
116
- version: '13.0'
130
+ version: 13.2.1
117
131
  - !ruby/object:Gem::Dependency
118
132
  name: sprockets-rails
119
133
  requirement: !ruby/object:Gem::Requirement
120
134
  requirements:
121
135
  - - "~>"
122
136
  - !ruby/object:Gem::Version
123
- version: 3.4.2
137
+ version: 3.5.2
124
138
  type: :development
125
139
  prerelease: false
126
140
  version_requirements: !ruby/object:Gem::Requirement
127
141
  requirements:
128
142
  - - "~>"
129
143
  - !ruby/object:Gem::Version
130
- version: 3.4.2
144
+ version: 3.5.2
131
145
  - !ruby/object:Gem::Dependency
132
146
  name: sqlite3
133
147
  requirement: !ruby/object:Gem::Requirement
134
148
  requirements:
135
149
  - - "~>"
136
150
  - !ruby/object:Gem::Version
137
- version: 1.6.3
151
+ version: 2.1.0
138
152
  type: :development
139
153
  prerelease: false
140
154
  version_requirements: !ruby/object:Gem::Requirement
141
155
  requirements:
142
156
  - - "~>"
143
157
  - !ruby/object:Gem::Version
144
- version: 1.6.3
158
+ version: 2.1.0
145
159
  - !ruby/object:Gem::Dependency
146
160
  name: codecov
147
161
  requirement: !ruby/object:Gem::Requirement
148
162
  requirements:
149
163
  - - "~>"
150
164
  - !ruby/object:Gem::Version
151
- version: 0.2.12
165
+ version: 0.6.0
152
166
  type: :development
153
167
  prerelease: false
154
168
  version_requirements: !ruby/object:Gem::Requirement
155
169
  requirements:
156
170
  - - "~>"
157
171
  - !ruby/object:Gem::Version
158
- version: 0.2.12
172
+ version: 0.6.0
159
173
  - !ruby/object:Gem::Dependency
160
174
  name: debug
161
175
  requirement: !ruby/object:Gem::Requirement
162
176
  requirements:
163
177
  - - "~>"
164
178
  - !ruby/object:Gem::Version
165
- version: 1.8.0
179
+ version: 1.9.2
166
180
  type: :development
167
181
  prerelease: false
168
182
  version_requirements: !ruby/object:Gem::Requirement
169
183
  requirements:
170
184
  - - "~>"
171
185
  - !ruby/object:Gem::Version
172
- version: 1.8.0
186
+ version: 1.9.2
173
187
  - !ruby/object:Gem::Dependency
174
188
  name: simplecov
175
189
  requirement: !ruby/object:Gem::Requirement
176
190
  requirements:
177
191
  - - "~>"
178
192
  - !ruby/object:Gem::Version
179
- version: 0.22.0
193
+ version: 0.21.2
180
194
  type: :development
181
195
  prerelease: false
182
196
  version_requirements: !ruby/object:Gem::Requirement
183
197
  requirements:
184
198
  - - "~>"
185
199
  - !ruby/object:Gem::Version
186
- version: 0.22.0
200
+ version: 0.21.2
187
201
  - !ruby/object:Gem::Dependency
188
202
  name: reek
189
203
  requirement: !ruby/object:Gem::Requirement
190
204
  requirements:
191
205
  - - "~>"
192
206
  - !ruby/object:Gem::Version
193
- version: 6.1.4
207
+ version: 6.3.0
194
208
  type: :development
195
209
  prerelease: false
196
210
  version_requirements: !ruby/object:Gem::Requirement
197
211
  requirements:
198
212
  - - "~>"
199
213
  - !ruby/object:Gem::Version
200
- version: 6.1.4
214
+ version: 6.3.0
201
215
  - !ruby/object:Gem::Dependency
202
216
  name: factory_bot_rails
203
217
  requirement: !ruby/object:Gem::Requirement
204
218
  requirements:
205
219
  - - "~>"
206
220
  - !ruby/object:Gem::Version
207
- version: 6.2.0
221
+ version: 6.4.3
208
222
  type: :development
209
223
  prerelease: false
210
224
  version_requirements: !ruby/object:Gem::Requirement
211
225
  requirements:
212
226
  - - "~>"
213
227
  - !ruby/object:Gem::Version
214
- version: 6.2.0
228
+ version: 6.4.3
215
229
  - !ruby/object:Gem::Dependency
216
230
  name: generator_spec
217
231
  requirement: !ruby/object:Gem::Requirement
218
232
  requirements:
219
233
  - - "~>"
220
234
  - !ruby/object:Gem::Version
221
- version: 0.9.4
235
+ version: 0.10.0
222
236
  type: :development
223
237
  prerelease: false
224
238
  version_requirements: !ruby/object:Gem::Requirement
225
239
  requirements:
226
240
  - - "~>"
227
241
  - !ruby/object:Gem::Version
228
- version: 0.9.4
242
+ version: 0.10.0
229
243
  - !ruby/object:Gem::Dependency
230
244
  name: rspec
231
245
  requirement: !ruby/object:Gem::Requirement
232
246
  requirements:
233
247
  - - "~>"
234
248
  - !ruby/object:Gem::Version
235
- version: '3.0'
249
+ version: 3.13.0
236
250
  type: :development
237
251
  prerelease: false
238
252
  version_requirements: !ruby/object:Gem::Requirement
239
253
  requirements:
240
254
  - - "~>"
241
255
  - !ruby/object:Gem::Version
242
- version: '3.0'
256
+ version: 3.13.0
243
257
  - !ruby/object:Gem::Dependency
244
258
  name: rspec-rails
245
259
  requirement: !ruby/object:Gem::Requirement
246
260
  requirements:
247
261
  - - "~>"
248
262
  - !ruby/object:Gem::Version
249
- version: 6.0.3
263
+ version: 7.0.1
250
264
  type: :development
251
265
  prerelease: false
252
266
  version_requirements: !ruby/object:Gem::Requirement
253
267
  requirements:
254
268
  - - "~>"
255
269
  - !ruby/object:Gem::Version
256
- version: 6.0.3
270
+ version: 7.0.1
257
271
  - !ruby/object:Gem::Dependency
258
272
  name: timecop
259
273
  requirement: !ruby/object:Gem::Requirement
260
274
  requirements:
261
275
  - - "~>"
262
276
  - !ruby/object:Gem::Version
263
- version: 0.9.6
277
+ version: 0.9.10
264
278
  type: :development
265
279
  prerelease: false
266
280
  version_requirements: !ruby/object:Gem::Requirement
267
281
  requirements:
268
282
  - - "~>"
269
283
  - !ruby/object:Gem::Version
270
- version: 0.9.6
284
+ version: 0.9.10
271
285
  - !ruby/object:Gem::Dependency
272
286
  name: rubocop
273
287
  requirement: !ruby/object:Gem::Requirement
274
288
  requirements:
275
289
  - - "~>"
276
290
  - !ruby/object:Gem::Version
277
- version: '1.21'
291
+ version: 1.66.1
278
292
  type: :development
279
293
  prerelease: false
280
294
  version_requirements: !ruby/object:Gem::Requirement
281
295
  requirements:
282
296
  - - "~>"
283
297
  - !ruby/object:Gem::Version
284
- version: '1.21'
298
+ version: 1.66.1
285
299
  - !ruby/object:Gem::Dependency
286
300
  name: rubocop-performance
287
301
  requirement: !ruby/object:Gem::Requirement
288
302
  requirements:
289
303
  - - "~>"
290
304
  - !ruby/object:Gem::Version
291
- version: 1.18.0
305
+ version: 1.22.1
292
306
  type: :development
293
307
  prerelease: false
294
308
  version_requirements: !ruby/object:Gem::Requirement
295
309
  requirements:
296
310
  - - "~>"
297
311
  - !ruby/object:Gem::Version
298
- version: 1.18.0
312
+ version: 1.22.1
299
313
  - !ruby/object:Gem::Dependency
300
314
  name: rubocop-rails
301
315
  requirement: !ruby/object:Gem::Requirement
302
316
  requirements:
303
317
  - - "~>"
304
318
  - !ruby/object:Gem::Version
305
- version: 2.20.2
319
+ version: 2.26.2
306
320
  type: :development
307
321
  prerelease: false
308
322
  version_requirements: !ruby/object:Gem::Requirement
309
323
  requirements:
310
324
  - - "~>"
311
325
  - !ruby/object:Gem::Version
312
- version: 2.20.2
326
+ version: 2.26.2
313
327
  - !ruby/object:Gem::Dependency
314
328
  name: rubocop-rake
315
329
  requirement: !ruby/object:Gem::Requirement
@@ -325,19 +339,61 @@ dependencies:
325
339
  - !ruby/object:Gem::Version
326
340
  version: 0.6.0
327
341
  - !ruby/object:Gem::Dependency
328
- name: rubocop-rspec
342
+ name: rubocop-rspec_rails
343
+ requirement: !ruby/object:Gem::Requirement
344
+ requirements:
345
+ - - "~>"
346
+ - !ruby/object:Gem::Version
347
+ version: 2.30.0
348
+ type: :development
349
+ prerelease: false
350
+ version_requirements: !ruby/object:Gem::Requirement
351
+ requirements:
352
+ - - "~>"
353
+ - !ruby/object:Gem::Version
354
+ version: 2.30.0
355
+ - !ruby/object:Gem::Dependency
356
+ name: rubocop-factory_bot
357
+ requirement: !ruby/object:Gem::Requirement
358
+ requirements:
359
+ - - "~>"
360
+ - !ruby/object:Gem::Version
361
+ version: 2.26.1
362
+ type: :development
363
+ prerelease: false
364
+ version_requirements: !ruby/object:Gem::Requirement
365
+ requirements:
366
+ - - "~>"
367
+ - !ruby/object:Gem::Version
368
+ version: 2.26.1
369
+ - !ruby/object:Gem::Dependency
370
+ name: danger-changelog
371
+ requirement: !ruby/object:Gem::Requirement
372
+ requirements:
373
+ - - "~>"
374
+ - !ruby/object:Gem::Version
375
+ version: 0.7.0
376
+ type: :development
377
+ prerelease: false
378
+ version_requirements: !ruby/object:Gem::Requirement
379
+ requirements:
380
+ - - "~>"
381
+ - !ruby/object:Gem::Version
382
+ version: 0.7.0
383
+ - !ruby/object:Gem::Dependency
384
+ name: danger-toc
329
385
  requirement: !ruby/object:Gem::Requirement
330
386
  requirements:
331
387
  - - "~>"
332
388
  - !ruby/object:Gem::Version
333
- version: 2.22.0
389
+ version: 0.2.0
334
390
  type: :development
335
391
  prerelease: false
336
392
  version_requirements: !ruby/object:Gem::Requirement
337
393
  requirements:
338
394
  - - "~>"
339
395
  - !ruby/object:Gem::Version
340
- version: 2.22.0
396
+ version: 0.2.0
341
397
  description: Devise is awesome, but we don't need all that UI/UX for PassKeys. This
342
398
  gem is to make it easy to provide a back end that authenticates a mobile front end
343
399
  with PassKeys.
@@ -380,6 +436,7 @@ files:
380
436
  - lib/generators/passkeys_rails/templates/README
381
437
  - lib/generators/passkeys_rails/templates/passkeys_rails_config.rb
382
438
  - lib/passkeys-rails.rb
439
+ - lib/passkeys_rails/configuration.rb
383
440
  - lib/passkeys_rails/engine.rb
384
441
  - lib/passkeys_rails/railtie.rb
385
442
  - lib/passkeys_rails/test/integration_helpers.rb
@@ -408,7 +465,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
408
465
  - !ruby/object:Gem::Version
409
466
  version: '0'
410
467
  requirements: []
411
- rubygems_version: 3.4.17
468
+ rubygems_version: 3.4.21
412
469
  signing_key:
413
470
  specification_version: 4
414
471
  summary: PassKey authentication back end with simple API