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 +4 -4
- data/CHANGELOG.md +40 -28
- data/README.md +141 -106
- data/app/controllers/passkeys_rails/passkeys_controller.rb +12 -4
- data/app/interactors/passkeys_rails/begin_challenge.rb +2 -2
- data/app/interactors/passkeys_rails/begin_registration.rb +2 -0
- data/app/interactors/passkeys_rails/finish_registration.rb +6 -2
- data/lib/generators/passkeys_rails/templates/passkeys_rails_config.rb +41 -0
- data/lib/passkeys-rails.rb +25 -42
- data/lib/passkeys_rails/configuration.rb +62 -0
- data/lib/passkeys_rails/version.rb +1 -1
- metadata +105 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8aeb76eb5817dbc1b1fac8a6205b5154772bd04d91f45596952b9b10e319f997
|
4
|
+
data.tar.gz: 0f3eb68558500c17ea980a1a1e0b00db8ddf13dfead9ef8568fb8a8d295f96ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f136f27de81f280d9d8e55e96b2f7c4729ded92a7b9c0339f0c766d0b8604732de430dd5f6e082ed700dca9422cc3c1af975dfae74aa267757d955b3bc15733
|
7
|
+
data.tar.gz: 92587364bdb4f41aa35dfaeef432bab42e77d6dd4a8e49b6797b12bd2a42f4ef0ecd9ed6dca5575abf3e068c0005c998d863f3eb7b1443eb4d01ac2271f73205
|
data/CHANGELOG.md
CHANGED
@@ -1,53 +1,65 @@
|
|
1
|
-
### 0.3.
|
1
|
+
### 0.3.2 (2024/10/01)
|
2
2
|
|
3
|
-
|
4
|
-
|
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.
|
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
|
-
|
26
|
+
- Added passkeys/debug_login functionality.
|
15
27
|
|
16
|
-
### 0.1.7
|
28
|
+
### 0.1.7 (2023/07/26)
|
17
29
|
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
44
|
+
- Changed namespace from Passkeys::Rails to PasskeysRails
|
33
45
|
|
34
|
-
### 0.1.3
|
46
|
+
### 0.1.3 (2023/07/23)
|
35
47
|
|
36
|
-
|
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
|
-
|
53
|
+
- Restructured lib directory.
|
42
54
|
|
43
|
-
|
55
|
+
- Fixed naming convention for gem/gemspec.
|
44
56
|
|
45
|
-
|
57
|
+
- Fixed exception handling.
|
46
58
|
|
47
|
-
### 0.1.1
|
59
|
+
### 0.1.1 (2023/07/23)
|
48
60
|
|
49
|
-
|
61
|
+
- Fixed dependency
|
50
62
|
|
51
|
-
### 0.1.0
|
63
|
+
### 0.1.0 (2023/07/23)
|
52
64
|
|
53
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
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 "
|
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
|
-
|
80
|
+
<a id="rails-Integration-standard"></a>
|
81
|
+
## Rails Integration <p><small>Adding to a standard rails project</small></p>
|
64
82
|
|
65
|
-
|
83
|
+
- ### Add `before_action :authenticate_passkey!`
|
66
84
|
|
67
|
-
|
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
|
-
|
87
|
+
- ### Use `current_agent` and `current_agent.authenticatable`
|
70
88
|
|
71
|
-
|
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
|
-
|
95
|
+
<a id="rails-Integration-grape"></a>
|
96
|
+
## Rails Integration - <p><small>Adding to a Grape API rails project</small></p>
|
76
97
|
|
77
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
137
|
+
## Notifications
|
138
|
+
|
139
|
+
Certain actions trigger notifications that can be subscribed. See `subscribe` in `config/initializers/passkeys_rails.rb`.
|
117
140
|
|
118
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
246
|
+
1. Passkey endpoints (for supporting authentication)
|
220
247
|
|
221
|
-
**Unauthenticated endpoints** can be consumed without
|
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
|
-
|
290
|
+
### POST /passkeys/challenge
|
253
291
|
|
254
292
|
Submit this to begin registration or authentication.
|
255
293
|
|
256
|
-
|
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
|
-
|
261
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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.
|
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.
|
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.
|
408
|
+
1. Use the response as if it was from `/passkeys/register`.
|
365
409
|
|
366
|
-
|
410
|
+
If you supply a username that doesn't match the `DEBUG_LOGIN_REGEX`, the endpoint will respond with an error.
|
367
411
|
|
368
|
-
|
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
|
-
-
|
382
|
-
|
383
|
-
|
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
|
-
###
|
430
|
+
### POST /passkeys/debug_login
|
390
431
|
|
391
|
-
|
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
|
-
|
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
|
-
|
436
|
+
To use this endpoint:
|
410
437
|
|
411
|
-
|
438
|
+
1. Manually create one or more PasskeysRails::Agent records in the database. A unique username is required for each.
|
412
439
|
|
413
|
-
|
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
|
-
|
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
|
-
|
444
|
+
1. Use the response as if it was from `/passkeys/authenticate`.
|
418
445
|
|
419
|
-
|
446
|
+
If you supply a username that doesn't match the `DEBUG_LOGIN_REGEX`, the endpoint will respond with an error.
|
420
447
|
|
421
|
-
|
448
|
+
Supply the following JSON structure:
|
422
449
|
|
423
|
-
|
450
|
+
```JSON
|
451
|
+
# POST body
|
452
|
+
{
|
453
|
+
"username": String
|
454
|
+
}
|
455
|
+
```
|
456
|
+
On **success**, the response is an `AuthResponse`.
|
424
457
|
|
425
|
-
|
458
|
+
Possible **failure codes** (using the `ErrorResponse` structure) are:
|
426
459
|
|
427
|
-
-
|
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
|
-
|
463
|
+
## Reference/Example Mobile Applications
|
430
464
|
|
431
|
-
|
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
|
-
|
467
|
+
Check out the [PasskeysRailsDemo](https://github.com/alliedcode/PasskeysRailsDemo) app.
|
434
468
|
|
435
|
-
|
469
|
+
## Contributing
|
436
470
|
|
437
|
-
|
471
|
+
### Contribution Guidelines
|
438
472
|
|
439
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
19
|
-
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:
|
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.
|
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
|
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
|
-
|
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
|
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
|
data/lib/passkeys-rails.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
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
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
18
|
+
def config
|
19
|
+
@config ||= begin
|
20
|
+
config = Configuration.new
|
21
|
+
yield(config) if block_given?
|
22
|
+
apply_webauthn_configuration(config)
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
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.
|
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:
|
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.
|
19
|
+
version: '7.2'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 7.
|
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.
|
29
|
+
version: '7.2'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 7.
|
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.
|
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.
|
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.
|
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.
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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:
|
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:
|
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:
|
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:
|
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.
|
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.
|
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:
|
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:
|
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.
|
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.
|
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.
|
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.
|
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-
|
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.
|
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.
|
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.
|
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
|