doorkeeper-device_authorization_grant 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +320 -0
- data/Rakefile +34 -0
- data/app/controllers/doorkeeper/device_authorization_grant/device_authorizations_controller.rb +68 -0
- data/app/controllers/doorkeeper/device_authorization_grant/device_codes_controller.rb +28 -0
- data/app/views/doorkeeper/device_authorization_grant/device_authorizations/index.html.erb +19 -0
- data/config/locales/en.yml +15 -0
- data/db/migrate/20200629094624_create_doorkeeper_device_grants.rb +28 -0
- data/lib/doorkeeper/device_authorization_grant.rb +47 -0
- data/lib/doorkeeper/device_authorization_grant/config.rb +92 -0
- data/lib/doorkeeper/device_authorization_grant/engine.rb +12 -0
- data/lib/doorkeeper/device_authorization_grant/errors.rb +43 -0
- data/lib/doorkeeper/device_authorization_grant/oauth/device_authorization_request.rb +88 -0
- data/lib/doorkeeper/device_authorization_grant/oauth/device_authorization_response.rb +73 -0
- data/lib/doorkeeper/device_authorization_grant/oauth/device_code_request.rb +105 -0
- data/lib/doorkeeper/device_authorization_grant/oauth/helpers/user_code.rb +39 -0
- data/lib/doorkeeper/device_authorization_grant/orm/active_record.rb +27 -0
- data/lib/doorkeeper/device_authorization_grant/orm/active_record/device_grant.rb +150 -0
- data/lib/doorkeeper/device_authorization_grant/rails/routes.rb +65 -0
- data/lib/doorkeeper/device_authorization_grant/rails/routes/mapper.rb +40 -0
- data/lib/doorkeeper/device_authorization_grant/rails/routes/mapping.rb +49 -0
- data/lib/doorkeeper/device_authorization_grant/request/device_authorization.rb +38 -0
- data/lib/doorkeeper/device_authorization_grant/version.rb +8 -0
- data/lib/doorkeeper/request/device_code.rb +33 -0
- data/lib/generators/doorkeeper/device_authorization_grant/install_generator.rb +16 -0
- data/lib/generators/doorkeeper/device_authorization_grant/templates/initializer.rb +33 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 41a11fbc4e3f17a41ba597414e90d134d92f121ed56ee0ab3fbd3289d5a8c000
|
4
|
+
data.tar.gz: 7662d33b032f9293c09ebdcfeef4afc2e6fabdbb5da6adf36baf2ac48d2d1ab6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c7c692bfa261c432498e68a300f657ed532471f6c3414b8d7def3c1c27c1f0e3424a3ddba99c19d6eb274d6aecd8a5f6d14d5a593e651bdb659aa455498a8ccb
|
7
|
+
data.tar.gz: b7de6fc069d86e5c2ec3dd3e2f94dc645ffef57934747dd2d9d3ee30bc3a0c7b529632c57e215de3302988db49ef88e994f08eafdc161327c87268bbec205ddf
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2020 EXOP Group
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
# Doorkeeper::DeviceAuthorizationGrant
|
2
|
+
|
3
|
+
OAuth 2.0 device authorization grant extension for Doorkeeper.
|
4
|
+
|
5
|
+
This library implements the OAuth 2.0 device authorization grant
|
6
|
+
([RFC 8628](https://tools.ietf.org/html/rfc8628)) for
|
7
|
+
[Ruby on Rails](https://rubyonrails.org/) applications on top of the
|
8
|
+
[Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) OAuth 2.0 framework.
|
9
|
+
|
10
|
+
## Status
|
11
|
+
|
12
|
+
This extension currently works with Doorkeeper version `>= 5.4.0`.
|
13
|
+
|
14
|
+
As of June 25 2020, due to some limitations of Doorkeeper, it is currently
|
15
|
+
inconvenient for this Gem to use the official OAuth grant type
|
16
|
+
`urn:ietf:params:oauth:grant-type:device_code`. Instead, it has been renamed
|
17
|
+
to simply `device_code`, which is non-standard. This is going to be corrected
|
18
|
+
soon: the next Doorkeeper release will include the ability to cleanly
|
19
|
+
register custom Grant Flows - see [Doorkeeper Pull Request #1418](https://github.com/doorkeeper-gem/doorkeeper/pull/1418).
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'doorkeeper-device_authorization_grant'
|
27
|
+
```
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
$ bundle
|
33
|
+
```
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
```bash
|
38
|
+
$ gem install doorkeeper-device_authorization_grant
|
39
|
+
```
|
40
|
+
|
41
|
+
Run the installation generator to update routes and create a dedicated initializer:
|
42
|
+
|
43
|
+
```bash
|
44
|
+
$ rails generate doorkeeper:device_authorization_grant:install
|
45
|
+
```
|
46
|
+
|
47
|
+
Generate a migration for Active Record (other ORMs are currently not supported):
|
48
|
+
|
49
|
+
```bash
|
50
|
+
$ rails doorkeeper_device_authorization_grant_engine:install:migrations
|
51
|
+
```
|
52
|
+
|
53
|
+
## Configuration
|
54
|
+
|
55
|
+
### Doorkeeper configuration
|
56
|
+
|
57
|
+
In your Doorkeeper initializer (usually `config/initializers/doorkeeper.rb`), enable
|
58
|
+
the device flow extension grant type, adding to the `grant_flows` option the `device_code`
|
59
|
+
string. For example:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
# config/initializers/doorkeeper.rb
|
63
|
+
|
64
|
+
Doorkeeper.configure do
|
65
|
+
# ...
|
66
|
+
|
67
|
+
grant_flows [
|
68
|
+
# Note: this is a non-standard grant flow, used instead of the
|
69
|
+
# official `urn:ietf:params:oauth:grant-type:device_code` due to
|
70
|
+
# current Doorkeeper limitations.
|
71
|
+
'device_code',
|
72
|
+
|
73
|
+
# together with all the other grant flows you already enabled, for example:
|
74
|
+
'authorization_code',
|
75
|
+
'client_credentials'
|
76
|
+
# ...
|
77
|
+
]
|
78
|
+
|
79
|
+
# ...
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
Please note that **this is not the official grant flow**. The real one should be
|
84
|
+
the IANA URN `urn:ietf:params:oauth:grant-type:device_code`, however this is hard
|
85
|
+
to support with the current version of Doorkeeper, due to how strategy classes are
|
86
|
+
looked up by grant type value.
|
87
|
+
|
88
|
+
### Device Authorization Grant configuration
|
89
|
+
|
90
|
+
The gem's installation scripts automatically creates a new initializer file:
|
91
|
+
`config/initializers/doorkeeper_device_authorization_grant.rb`. Here you can
|
92
|
+
adjust the configuration parameters according to your needs.
|
93
|
+
|
94
|
+
### Routes
|
95
|
+
|
96
|
+
The gem's installation scripts automatically modify your `config/routes.rb`
|
97
|
+
file, adding the default routes to the controllers described above. The
|
98
|
+
routes file should then look like this:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Rails.application.routes.draw do
|
102
|
+
use_doorkeeper_device_authorization_grant
|
103
|
+
# your routes ...
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
This is enough to add to your app the following default routes:
|
108
|
+
|
109
|
+
```
|
110
|
+
Prefix Verb URI Controller#Action
|
111
|
+
oauth_device_codes_create POST /oauth/authorize_device doorkeeper/device_authorization_grant/device_codes#create
|
112
|
+
oauth_device_authorizations_index GET /oauth/device doorkeeper/device_authorization_grant/device_authorizations#index
|
113
|
+
oauth_device_authorizations_authorize POST /oauth/device doorkeeper/device_authorization_grant/device_authorizations#authorize
|
114
|
+
```
|
115
|
+
|
116
|
+
The routing method `use_doorkeeper_device_authorization_grant` allows extra customization,
|
117
|
+
just like `use_doorkeeper` (see [Doorkeeper Wiki - Customizing routes](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes)).
|
118
|
+
|
119
|
+
This Gem defines two Rails controllers:
|
120
|
+
|
121
|
+
- `DeviceCodesController` serves Device Authorization requests, as described
|
122
|
+
by [RFC 8628](https://tools.ietf.org/html/rfc8628), sections 3.1
|
123
|
+
and 3.2.
|
124
|
+
- `DeviceAuthorizationsController` provides a bare-bones implementation of a
|
125
|
+
verification web page which allows an authenticated resource-owner to
|
126
|
+
authorize a device, by providing an end-user code.
|
127
|
+
|
128
|
+
You can change the controllers to your **custom controllers** with the `controller` option:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
Rails.application.routes.draw do
|
132
|
+
use_doorkeeper_device_authorization_grant do
|
133
|
+
# it accepts :device_authorizations and :device_codes
|
134
|
+
controller device_authorizations: 'custom_device_authorizations'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
Be sure to use the same superclasses of the original controllers (or something compatible).
|
140
|
+
|
141
|
+
You can set **custom aliases** with `as`:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
Rails.application.routes.draw do
|
145
|
+
use_doorkeeper_device_authorization_grant do
|
146
|
+
# it accepts :device_authorizations and :device_codes
|
147
|
+
as device_codes: :custom_device
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
You can **skip routes** with `skip_controllers`:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
Rails.application.routes.draw do
|
156
|
+
use_doorkeeper_device_authorization_grant do
|
157
|
+
# it accepts :device_authorizations and :device_codes
|
158
|
+
skip_controllers :device_authorizations
|
159
|
+
end
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
The default scope is `oauth`. You can provide a **custom scope** like this:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
Rails.application.routes.draw do
|
167
|
+
use_doorkeeper_device_authorization_grant scope: 'oauth2'
|
168
|
+
end
|
169
|
+
```
|
170
|
+
|
171
|
+
## Usage
|
172
|
+
|
173
|
+
The following sections show the typical steps of a device authorization flow.
|
174
|
+
Default configuration and routes are assumed.
|
175
|
+
|
176
|
+
### Device Authorization Request
|
177
|
+
|
178
|
+
Reference: [RFC 8628, section 3.1 - Device Authorization Request](https://tools.ietf.org/html/rfc8628#section-3.1).
|
179
|
+
|
180
|
+
First of all, a *Device Client* can perform a *Device Authorization Request* to
|
181
|
+
the *Authorization Server* (your Rails application, with Doorkeeper and this
|
182
|
+
gem extension) like this:
|
183
|
+
|
184
|
+
```http request
|
185
|
+
POST /oauth/authorize_device HTTP/1.1
|
186
|
+
Content-Type: application/x-www-form-urlencoded
|
187
|
+
|
188
|
+
client_id=1406020730&scope=example_scope
|
189
|
+
```
|
190
|
+
|
191
|
+
### Device Authorization Response
|
192
|
+
|
193
|
+
Reference: [RFC 8628, section 3.2 - Device Authorization Response](https://tools.ietf.org/html/rfc8628#section-3.2).
|
194
|
+
|
195
|
+
The *Authorization Server* responds with a *Device Authorization Response*:
|
196
|
+
|
197
|
+
```
|
198
|
+
HTTP/1.1 200 OK
|
199
|
+
Content-Type: application/json
|
200
|
+
|
201
|
+
{
|
202
|
+
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
|
203
|
+
"user_code": "0A44L90H",
|
204
|
+
"verification_uri": "https://example.com/oauth/device",
|
205
|
+
"verification_uri_complete": "https://example.com/oauth/device?user_code=0A44L90H",
|
206
|
+
"expires_in": 300,
|
207
|
+
"interval": 5
|
208
|
+
}
|
209
|
+
```
|
210
|
+
|
211
|
+
### User interaction
|
212
|
+
|
213
|
+
Reference: [RFC 8628, section 3.3 - User Interaction](https://tools.ietf.org/html/rfc8628#section-3.3).
|
214
|
+
|
215
|
+
The *Device Client* can now display to the end user the `user_code` and the
|
216
|
+
`verification_uri` (or somehow make use of `verification_uri_complete`, in special cases).
|
217
|
+
|
218
|
+
The user should visit URI in a user agent on a secondary device (for example, in a browser
|
219
|
+
on their mobile phone) and enter the user code.
|
220
|
+
|
221
|
+
During the user interaction, the device continuously polls the token endpoint with the
|
222
|
+
`device_code`, as detailed in the next section, until the user completes the interaction,
|
223
|
+
the code expires, or another error occurs.
|
224
|
+
|
225
|
+
The default Rails route provided by this Gem, `/oauth/device`, allows an authenticated
|
226
|
+
request owner (for example, a user) to manually verify the user code.
|
227
|
+
|
228
|
+
### Device Access Token Request / polling
|
229
|
+
|
230
|
+
Reference: [RFC 8628, section 3.4 - Device Access Token Request](https://tools.ietf.org/html/rfc8628#section-3.4).
|
231
|
+
|
232
|
+
After displaying instructions to the user, the *Device Client* should create a
|
233
|
+
*Device Access Token Request* and send it to the token endpoint (provided
|
234
|
+
by Dorkeeper), for example:
|
235
|
+
|
236
|
+
```http request
|
237
|
+
POST /oauth/token HTTP/1.1
|
238
|
+
Content-Type: application/x-www-form-urlencoded
|
239
|
+
|
240
|
+
grant_type=device_code
|
241
|
+
&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
|
242
|
+
&client_id=1406020730
|
243
|
+
```
|
244
|
+
|
245
|
+
**Note:** this is a non-standard `grant_type`, used instead of the official
|
246
|
+
`urn:ietf:params:oauth:grant-type:device_code` due to current limitations of
|
247
|
+
the Doorkeeper gem.
|
248
|
+
|
249
|
+
The response to this request is defined in the next section. It is expected for
|
250
|
+
the *Device Client* to try the access token request repeatedly in a polling
|
251
|
+
fashion, based on the error code in the response. The polling time interval
|
252
|
+
was possibly included in the *Device Authorization Response*, but it is
|
253
|
+
optional; if no value was provided, the client MUST use 5 seconds as the default.
|
254
|
+
|
255
|
+
### Device Access Token Response
|
256
|
+
|
257
|
+
Reference: [RFC 8628, section 3.5 - Device Access Token Response](https://tools.ietf.org/html/rfc8628#section-3.5).
|
258
|
+
|
259
|
+
Please refer to the RFC document for exhaustive documentation. Here we show just
|
260
|
+
some possible responses.
|
261
|
+
|
262
|
+
While the authorization request is still pending, and the device-code token is
|
263
|
+
not expired, the response contains an `authorization_pending` error:
|
264
|
+
|
265
|
+
```
|
266
|
+
HTTP/1.1 400 Bad Request
|
267
|
+
Content-Type: application/json
|
268
|
+
|
269
|
+
{ "error": "authorization_pending", "error_description": "..." }
|
270
|
+
```
|
271
|
+
|
272
|
+
The client should simply continue with further polling requests.
|
273
|
+
|
274
|
+
If the client requests are too close in time, a `slow_down` error is returned:
|
275
|
+
|
276
|
+
```
|
277
|
+
HTTP/1.1 400 Bad Request
|
278
|
+
Content-Type: application/json
|
279
|
+
|
280
|
+
{ "error": "slow_down", "error_description": "..." }
|
281
|
+
```
|
282
|
+
|
283
|
+
The client can still continue with polling requests, but the polling time interval
|
284
|
+
MUST be increased by 5 seconds for all subsequent requests.
|
285
|
+
|
286
|
+
If the `device_code` has expired, the response contains the `expired_token` error:
|
287
|
+
|
288
|
+
```
|
289
|
+
HTTP/1.1 400 Bad Request
|
290
|
+
Content-Type: application/json
|
291
|
+
|
292
|
+
{ "error": "expired_token", "error_description": "..." }
|
293
|
+
```
|
294
|
+
|
295
|
+
The client should stop polling, and may commence a new device authorization
|
296
|
+
request (possibly upon waiting for further user interaction).
|
297
|
+
|
298
|
+
Once the user has successfully authorized the device, a successful response will
|
299
|
+
be eventually returned. This is a standard OAuth 2.0 response, described in
|
300
|
+
[Section 5.1 of [RFC6749]](https://tools.ietf.org/html/rfc6749#section-5.1). Here
|
301
|
+
is a typical bearer token response:
|
302
|
+
|
303
|
+
```
|
304
|
+
HTTP/1.1 200 OK
|
305
|
+
Content-Type: application/json
|
306
|
+
|
307
|
+
{
|
308
|
+
"access_token": "FkPeBMF8Ab0zkYj6vQLZCxZ5OP0Hrd7ST3RS99x7nRM",
|
309
|
+
"token_type": "Bearer",
|
310
|
+
"expires_in": 7200,
|
311
|
+
"scope": "read",
|
312
|
+
"created_at": 1593096829
|
313
|
+
}
|
314
|
+
```
|
315
|
+
|
316
|
+
The device authentication flow is now complete, and the token data can be used to
|
317
|
+
authenticate requests against the authorization and/or resource server.
|
318
|
+
|
319
|
+
## License
|
320
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rdoc/task'
|
10
|
+
|
11
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
12
|
+
rdoc.rdoc_dir = 'rdoc'
|
13
|
+
rdoc.title = 'Doorkeeper::DeviceAuthorizationGrant'
|
14
|
+
rdoc.options << '--line-numbers'
|
15
|
+
rdoc.rdoc_files.include('README.md')
|
16
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
|
+
end
|
18
|
+
|
19
|
+
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
20
|
+
load 'rails/tasks/engine.rake'
|
21
|
+
|
22
|
+
load 'rails/tasks/statistics.rake'
|
23
|
+
|
24
|
+
require 'bundler/gem_tasks'
|
25
|
+
|
26
|
+
require 'rake/testtask'
|
27
|
+
|
28
|
+
Rake::TestTask.new(:test) do |t|
|
29
|
+
t.libs << 'test'
|
30
|
+
t.pattern = 'test/**/*_test.rb'
|
31
|
+
t.verbose = false
|
32
|
+
end
|
33
|
+
|
34
|
+
task default: :test
|
data/app/controllers/doorkeeper/device_authorization_grant/device_authorizations_controller.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module DeviceAuthorizationGrant
|
5
|
+
# The Device Authorizations controller provides a simple interface which
|
6
|
+
# allows authenticated resource owners to authorize devices, by providing
|
7
|
+
# a user code.
|
8
|
+
class DeviceAuthorizationsController < Doorkeeper::ApplicationController
|
9
|
+
before_action :authenticate_resource_owner!
|
10
|
+
|
11
|
+
def index
|
12
|
+
respond_to do |format|
|
13
|
+
format.html
|
14
|
+
format.json { head :no_content }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def authorize
|
19
|
+
device_grant_model.transaction do
|
20
|
+
device_grant = device_grant_model.lock.find_by(user_code: user_code)
|
21
|
+
return authorization_error_response(:invalid_user_code) if device_grant.nil?
|
22
|
+
return authorization_error_response(:expired_user_code) if device_grant.expired?
|
23
|
+
|
24
|
+
device_grant.update!(user_code: nil, resource_owner_id: current_resource_owner.id)
|
25
|
+
end
|
26
|
+
|
27
|
+
authorization_success_response
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def authorization_success_response
|
33
|
+
respond_to do |format|
|
34
|
+
notice = I18n.t(:success, scope: i18n_flash_scope(:authorize))
|
35
|
+
format.html { redirect_to oauth_device_authorizations_index_url, notice: notice }
|
36
|
+
format.json { head :no_content }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param error_message_key [Symbol]
|
41
|
+
def authorization_error_response(error_message_key)
|
42
|
+
respond_to do |format|
|
43
|
+
notice = I18n.t(error_message_key, scope: i18n_flash_scope(:authorize))
|
44
|
+
format.html { redirect_to oauth_device_authorizations_index_url, notice: notice }
|
45
|
+
format.json do
|
46
|
+
render json: { errors: [notice] }, status: :unprocessable_entity
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Class]
|
52
|
+
def device_grant_model
|
53
|
+
@device_grant_model ||= Doorkeeper::DeviceAuthorizationGrant.configuration.device_grant_model
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [String, nil]
|
57
|
+
def user_code
|
58
|
+
params[:user_code]
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param action [Symbol]
|
62
|
+
# @return [Array<Symbol>]
|
63
|
+
def i18n_flash_scope(action)
|
64
|
+
%I[doorkeeper flash device_codes #{action}]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|