doorkeeper 5.1.2 → 5.2.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +1 -1
  3. data/CHANGELOG.md +880 -0
  4. data/CONTRIBUTING.md +11 -9
  5. data/Dangerfile +2 -2
  6. data/Dockerfile +29 -0
  7. data/Gemfile +3 -2
  8. data/NEWS.md +1 -819
  9. data/README.md +11 -3
  10. data/RELEASING.md +6 -5
  11. data/app/controllers/doorkeeper/application_controller.rb +1 -1
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +2 -1
  13. data/app/controllers/doorkeeper/applications_controller.rb +1 -0
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +14 -7
  15. data/app/controllers/doorkeeper/tokens_controller.rb +32 -9
  16. data/app/views/doorkeeper/applications/_form.html.erb +0 -6
  17. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  18. data/config/locales/en.yml +8 -2
  19. data/doorkeeper.gemspec +9 -1
  20. data/gemfiles/rails_5_0.gemfile +1 -0
  21. data/gemfiles/rails_5_1.gemfile +1 -0
  22. data/gemfiles/rails_5_2.gemfile +1 -0
  23. data/gemfiles/rails_6_0.gemfile +2 -1
  24. data/gemfiles/rails_master.gemfile +1 -0
  25. data/lib/doorkeeper/config/option.rb +13 -7
  26. data/lib/doorkeeper/config.rb +89 -6
  27. data/lib/doorkeeper/errors.rb +13 -18
  28. data/lib/doorkeeper/grape/helpers.rb +5 -1
  29. data/lib/doorkeeper/helpers/controller.rb +23 -4
  30. data/lib/doorkeeper/models/access_token_mixin.rb +49 -7
  31. data/lib/doorkeeper/oauth/authorization/code.rb +11 -13
  32. data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
  33. data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -9
  34. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  35. data/lib/doorkeeper/oauth/client_credentials/creator.rb +14 -0
  36. data/lib/doorkeeper/oauth/client_credentials/validation.rb +8 -0
  37. data/lib/doorkeeper/oauth/code_request.rb +5 -11
  38. data/lib/doorkeeper/oauth/code_response.rb +2 -2
  39. data/lib/doorkeeper/oauth/error_response.rb +1 -1
  40. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +18 -4
  41. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  42. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  43. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
  44. data/lib/doorkeeper/oauth/pre_authorization.rb +73 -37
  45. data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -10
  46. data/lib/doorkeeper/oauth/token_introspection.rb +23 -13
  47. data/lib/doorkeeper/oauth/token_request.rb +4 -18
  48. data/lib/doorkeeper/orm/active_record/access_grant.rb +1 -1
  49. data/lib/doorkeeper/orm/active_record/access_token.rb +2 -2
  50. data/lib/doorkeeper/orm/active_record/application.rb +13 -5
  51. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +61 -0
  52. data/lib/doorkeeper/orm/active_record.rb +18 -3
  53. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  54. data/lib/doorkeeper/request.rb +6 -11
  55. data/lib/doorkeeper/server.rb +2 -6
  56. data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
  57. data/lib/doorkeeper/version.rb +2 -2
  58. data/lib/doorkeeper.rb +4 -0
  59. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +6 -6
  60. data/lib/generators/doorkeeper/templates/initializer.rb +118 -33
  61. data/lib/generators/doorkeeper/templates/migration.rb.erb +4 -1
  62. data/spec/controllers/applications_controller_spec.rb +93 -0
  63. data/spec/controllers/authorizations_controller_spec.rb +143 -62
  64. data/spec/controllers/protected_resources_controller_spec.rb +3 -3
  65. data/spec/controllers/tokens_controller_spec.rb +205 -37
  66. data/spec/dummy/config/application.rb +3 -1
  67. data/spec/dummy/config/initializers/doorkeeper.rb +54 -9
  68. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +1 -1
  69. data/spec/lib/config_spec.rb +58 -1
  70. data/spec/lib/oauth/authorization_code_request_spec.rb +13 -1
  71. data/spec/lib/oauth/base_request_spec.rb +33 -16
  72. data/spec/lib/oauth/client_credentials/creator_spec.rb +3 -0
  73. data/spec/lib/oauth/code_request_spec.rb +27 -28
  74. data/spec/lib/oauth/helpers/uri_checker_spec.rb +17 -2
  75. data/spec/lib/oauth/invalid_request_response_spec.rb +75 -0
  76. data/spec/lib/oauth/pre_authorization_spec.rb +76 -66
  77. data/spec/lib/oauth/refresh_token_request_spec.rb +1 -0
  78. data/spec/lib/oauth/token_request_spec.rb +20 -17
  79. data/spec/lib/server_spec.rb +0 -12
  80. data/spec/models/doorkeeper/access_grant_spec.rb +21 -2
  81. data/spec/models/doorkeeper/access_token_spec.rb +35 -4
  82. data/spec/models/doorkeeper/application_spec.rb +10 -0
  83. data/spec/requests/endpoints/authorization_spec.rb +21 -5
  84. data/spec/requests/endpoints/token_spec.rb +1 -1
  85. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -0
  86. data/spec/requests/flows/authorization_code_spec.rb +93 -27
  87. data/spec/requests/flows/client_credentials_spec.rb +38 -0
  88. data/spec/requests/flows/implicit_grant_errors_spec.rb +22 -10
  89. data/spec/requests/flows/implicit_grant_spec.rb +9 -8
  90. data/spec/requests/flows/password_spec.rb +37 -0
  91. data/spec/requests/flows/refresh_token_spec.rb +1 -1
  92. data/spec/requests/flows/revoke_token_spec.rb +19 -11
  93. data/spec/support/doorkeeper_rspec.rb +1 -1
  94. data/spec/support/helpers/request_spec_helper.rb +14 -2
  95. data/spec/validators/redirect_uri_validator_spec.rb +40 -15
  96. metadata +16 -15
  97. data/.coveralls.yml +0 -1
  98. data/.github/ISSUE_TEMPLATE.md +0 -25
  99. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  100. data/.gitignore +0 -20
  101. data/.gitlab-ci.yml +0 -16
  102. data/.hound.yml +0 -3
  103. data/.rspec +0 -1
  104. data/.rubocop.yml +0 -50
  105. data/.travis.yml +0 -35
  106. data/app/validators/redirect_uri_validator.rb +0 -50
@@ -65,15 +65,6 @@ Doorkeeper.configure do
65
65
  # Check out the wiki for more information on customization
66
66
  # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
67
67
 
68
- # Change the native redirect uri for client apps
69
- # When clients register with the following redirect uri, they won't be redirected to any server and
70
- # the authorization code will be displayed within the provider
71
- # The value can be any string. Use nil to disable this feature.
72
- # When disabled, clients must provide a valid URL
73
- # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
74
- #
75
- # native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
76
-
77
68
  # Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
78
69
  # by default in non-development environments). OAuth2 delegates security in
79
70
  # communication to the HTTPS protocol so it is wise to keep this enabled.
@@ -116,6 +107,60 @@ Doorkeeper.configure do
116
107
  # client.superapp? or resource_owner.admin?
117
108
  # end
118
109
 
110
+ # Configure custom constraints for the Token Introspection request.
111
+ # By default this configuration option allows to introspect a token by another
112
+ # token of the same application, OR to introspect the token that belongs to
113
+ # authorized client (from authenticated client) OR when token doesn't
114
+ # belong to any client (public token). Otherwise requester has no access to the
115
+ # introspection and it will return response as stated in the RFC.
116
+ #
117
+ # Block arguments:
118
+ #
119
+ # @param token [Doorkeeper::AccessToken]
120
+ # token to be introspected
121
+ #
122
+ # @param authorized_client [Doorkeeper::Application]
123
+ # authorized client (if request is authorized using Basic auth with
124
+ # Client Credentials for example)
125
+ #
126
+ # @param authorized_token [Doorkeeper::AccessToken]
127
+ # Bearer token used to authorize the request
128
+ #
129
+ # In case the block returns `nil` or `false` introspection responses with 401 status code
130
+ # when using authorized token to introspect, or you'll get 200 with { "active": false } body
131
+ # when using authorized client to introspect as stated in the
132
+ # RFC 7662 section 2.2. Introspection Response.
133
+ #
134
+ # Using with caution:
135
+ # Keep in mind that these three parameters pass to block can be nil as following case:
136
+ # `authorized_client` is nil if and only if `authorized_token` is present, and vice versa.
137
+ # `token` will be nil if and only if `authorized_token` is present.
138
+ # So remember to use `&` or check if it is present before calling method on
139
+ # them to make sure you doesn't get NoMethodError exception.
140
+ #
141
+ # You can define your custom check:
142
+ #
143
+ # allow_token_introspection do |token, authorized_client, authorized_token|
144
+ # if authorized_token
145
+ # # customize: require `introspection` scope
146
+ # authorized_token.application == token&.application ||
147
+ # authorized_token.scopes.include?("introspection")
148
+ # elsif token.application
149
+ # # `protected_resource` is a new database boolean column, for example
150
+ # authorized_client == token.application || authorized_client.protected_resource?
151
+ # else
152
+ # # public token (when token.application is nil, token doesn't belong to any application)
153
+ # true
154
+ # end
155
+ # end
156
+ #
157
+ # Or you can completely disable any token introspection:
158
+ #
159
+ # allow_token_introspection false
160
+ #
161
+ # If you need to block the request at all, then configure your routes.rb or web-server
162
+ # like nginx to forbid the request.
163
+
119
164
  # WWW-Authenticate Realm (default "Doorkeeper").
120
165
  realm "Doorkeeper"
121
166
  end
@@ -25,7 +25,7 @@ class CreateDoorkeeperTables < ActiveRecord::Migration[4.2]
25
25
  t.text :redirect_uri, null: false
26
26
  t.datetime :created_at, null: false
27
27
  t.datetime :revoked_at
28
- t.string :scopes
28
+ t.string :scopes, null: false, default: ""
29
29
  end
30
30
 
31
31
  add_index :oauth_access_grants, :token, unique: true
@@ -502,7 +502,21 @@ describe Doorkeeper, "configuration" do
502
502
 
503
503
  describe "base_controller" do
504
504
  context "default" do
505
- it { expect(Doorkeeper.configuration.base_controller).to eq("ActionController::Base") }
505
+ it { expect(Doorkeeper.configuration.base_controller).to be_an_instance_of(Proc) }
506
+
507
+ it "resolves to a ApplicationController::Base in default mode" do
508
+ expect(Doorkeeper.configuration.resolve_controller(:base))
509
+ .to eq(ActionController::Base)
510
+ end
511
+
512
+ it "resolves to a ApplicationController::API in api_only mode" do
513
+ Doorkeeper.configure do
514
+ api_only
515
+ end
516
+
517
+ expect(Doorkeeper.configuration.resolve_controller(:base))
518
+ .to eq(ActionController::API)
519
+ end
506
520
  end
507
521
 
508
522
  context "custom" do
@@ -517,6 +531,23 @@ describe Doorkeeper, "configuration" do
517
531
  end
518
532
  end
519
533
 
534
+ describe "base_metal_controller" do
535
+ context "default" do
536
+ it { expect(Doorkeeper.configuration.base_metal_controller).to eq("ActionController::API") }
537
+ end
538
+
539
+ context "custom" do
540
+ before do
541
+ Doorkeeper.configure do
542
+ orm DOORKEEPER_ORM
543
+ base_metal_controller { "ApplicationController" }
544
+ end
545
+ end
546
+
547
+ it { expect(Doorkeeper.configuration.resolve_controller(:base_metal)).to eq(ApplicationController) }
548
+ end
549
+ end
550
+
520
551
  if DOORKEEPER_ORM == :active_record
521
552
  describe "active_record_options" do
522
553
  let(:models) { [Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application] }
@@ -557,6 +588,21 @@ describe Doorkeeper, "configuration" do
557
588
  end
558
589
  end
559
590
 
591
+ describe "token_lookup_batch_size" do
592
+ it "uses default doorkeeper value" do
593
+ expect(subject.token_lookup_batch_size).to eq(10_000)
594
+ end
595
+
596
+ it "can change the value" do
597
+ Doorkeeper.configure do
598
+ orm DOORKEEPER_ORM
599
+ token_lookup_batch_size 100_000
600
+ end
601
+
602
+ expect(subject.token_lookup_batch_size).to eq(100_000)
603
+ end
604
+ end
605
+
560
606
  describe "strict_content_type" do
561
607
  it "is false by default" do
562
608
  expect(subject.enforce_content_type).to eq(false)
@@ -694,4 +740,15 @@ describe Doorkeeper, "configuration" do
694
740
  end
695
741
  end
696
742
  end
743
+
744
+ describe "options deprecation" do
745
+ it "prints a warning message when an option is deprecated" do
746
+ expect(Kernel).to receive(:warn).with(
747
+ "[DOORKEEPER] native_redirect_uri has been deprecated and will soon be removed"
748
+ )
749
+ Doorkeeper.configure do
750
+ native_redirect_uri "urn:ietf:wg:oauth:2.0:oob"
751
+ end
752
+ end
753
+ end
697
754
  end
@@ -23,7 +23,7 @@ module Doorkeeper::OAuth
23
23
  end
24
24
 
25
25
  subject do
26
- AuthorizationCodeRequest.new server, grant, client, params
26
+ AuthorizationCodeRequest.new(server, grant, client, params)
27
27
  end
28
28
 
29
29
  it "issues a new token for the client" do
@@ -65,6 +65,18 @@ module Doorkeeper::OAuth
65
65
  subject.redirect_uri = nil
66
66
  subject.validate
67
67
  expect(subject.error).to eq(:invalid_request)
68
+ expect(subject.missing_param).to eq(:redirect_uri)
69
+ end
70
+
71
+ it "invalid code_verifier param because server does not support pkce" do
72
+ # Some other ORMs work relies on #respond_to? so it's not a good idea to stub it :\
73
+ allow_any_instance_of(Doorkeeper::AccessGrant).to receive(:respond_to?).with(anything).and_call_original
74
+ allow_any_instance_of(Doorkeeper::AccessGrant).to receive(:respond_to?).with(:code_challenge).and_return(false)
75
+
76
+ subject.code_verifier = "a45a9fea-0676-477e-95b1-a40f72ac3cfb"
77
+ subject.validate
78
+ expect(subject.error).to eq(:invalid_request)
79
+ expect(subject.invalid_request_reason).to eq(:not_support_pkce)
68
80
  end
69
81
 
70
82
  it "matches the redirect_uri with grant's one" do
@@ -66,27 +66,44 @@ module Doorkeeper::OAuth
66
66
  end
67
67
 
68
68
  context "invalid" do
69
- before do
70
- allow(subject).to receive(:valid?).and_return(false)
71
- allow(subject).to receive(:error).and_return("server_error")
72
- allow(subject).to receive(:state).and_return("hello")
69
+ context "with error other than invalid_request" do
70
+ before do
71
+ allow(subject).to receive(:valid?).and_return(false)
72
+ allow(subject).to receive(:error).and_return(:server_error)
73
+ allow(subject).to receive(:state).and_return("hello")
74
+ end
75
+
76
+ it "returns an ErrorResponse object" do
77
+ result = subject.authorize
78
+
79
+ expect(result).to be_an_instance_of(ErrorResponse)
80
+
81
+ expect(result.body).to eq(
82
+ error: :server_error,
83
+ error_description: translated_error_message(:server_error),
84
+ state: "hello"
85
+ )
86
+ end
73
87
  end
74
88
 
75
- it "returns an ErrorResponse object" do
76
- error_description = I18n.translate(
77
- "server_error",
78
- scope: %i[doorkeeper errors messages]
79
- )
89
+ context "with invalid_request error" do
90
+ before do
91
+ allow(subject).to receive(:valid?).and_return(false)
92
+ allow(subject).to receive(:error).and_return(:invalid_request)
93
+ allow(subject).to receive(:state).and_return("hello")
94
+ end
80
95
 
81
- result = subject.authorize
96
+ it "returns an InvalidRequestResponse object" do
97
+ result = subject.authorize
82
98
 
83
- expect(result).to be_an_instance_of(ErrorResponse)
99
+ expect(result).to be_an_instance_of(InvalidRequestResponse)
84
100
 
85
- expect(result.body).to eq(
86
- error: "server_error",
87
- error_description: error_description,
88
- state: "hello"
89
- )
101
+ expect(result.body).to eq(
102
+ error: :invalid_request,
103
+ error_description: translated_invalid_request_error_message(:unknown, :unknown),
104
+ state: "hello"
105
+ )
106
+ end
90
107
  end
91
108
  end
92
109
  end
@@ -55,6 +55,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
55
55
 
56
56
  expect(Doorkeeper::AccessToken.count).to eq(2)
57
57
  expect(result).not_to eq(existing_token)
58
+ expect(existing_token.reload).to be_revoked
58
59
  end
59
60
  end
60
61
 
@@ -69,6 +70,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
69
70
 
70
71
  expect(Doorkeeper::AccessToken.count).to eq(2)
71
72
  expect(result).not_to eq(existing_token)
73
+ expect(existing_token.reload).to be_revoked
72
74
  end
73
75
  end
74
76
  end
@@ -82,6 +84,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
82
84
 
83
85
  expect(Doorkeeper::AccessToken.count).to eq(2)
84
86
  expect(result).not_to eq(existing_token)
87
+ expect(existing_token.reload).to be_revoked
85
88
  end
86
89
  end
87
90
 
@@ -4,18 +4,23 @@ require "spec_helper"
4
4
 
5
5
  module Doorkeeper::OAuth
6
6
  describe CodeRequest do
7
- let(:pre_auth) do
8
- double(
9
- :pre_auth,
10
- client: double(:application, id: 9990),
11
- redirect_uri: "http://tst.com/cb",
12
- scopes: nil,
13
- state: nil,
14
- error: nil,
15
- authorizable?: true,
16
- code_challenge: nil,
17
- code_challenge_method: nil
18
- )
7
+ let :pre_auth do
8
+ server = Doorkeeper.configuration
9
+ allow(server).to receive(:default_scopes).and_return(Scopes.from_string("public"))
10
+ allow(server).to receive(:grant_flows).and_return(Scopes.from_string("authorization_code"))
11
+
12
+ application = FactoryBot.create(:application, scopes: "public")
13
+ client = Doorkeeper::OAuth::Client.new(application)
14
+
15
+ attributes = {
16
+ client_id: client.uid,
17
+ response_type: "code",
18
+ redirect_uri: "https://app.com/callback",
19
+ }
20
+
21
+ pre_auth = PreAuthorization.new(server, attributes)
22
+ pre_auth.authorizable?
23
+ pre_auth
19
24
  end
20
25
 
21
26
  let(:owner) { double :owner, id: 8900 }
@@ -24,24 +29,18 @@ module Doorkeeper::OAuth
24
29
  CodeRequest.new(pre_auth, owner)
25
30
  end
26
31
 
27
- it "creates an access grant" do
28
- expect do
29
- subject.authorize
30
- end.to change { Doorkeeper::AccessGrant.count }.by(1)
32
+ context "when pre_auth is authorized" do
33
+ it "creates an access grant and returns a code response" do
34
+ expect { subject.authorize }.to change { Doorkeeper::AccessGrant.count }.by(1)
35
+ expect(subject.authorize).to be_a(CodeResponse)
36
+ end
31
37
  end
32
38
 
33
- it "returns a code response" do
34
- expect(subject.authorize).to be_a(CodeResponse)
35
- end
36
-
37
- it "does not create grant when not authorizable" do
38
- allow(pre_auth).to receive(:authorizable?).and_return(false)
39
- expect { subject.authorize }.not_to(change { Doorkeeper::AccessGrant.count })
40
- end
41
-
42
- it "returns a error response" do
43
- allow(pre_auth).to receive(:authorizable?).and_return(false)
44
- expect(subject.authorize).to be_a(ErrorResponse)
39
+ context "when pre_auth is denied" do
40
+ it "does not create access grant and returns a error response" do
41
+ expect { subject.deny }.not_to(change { Doorkeeper::AccessGrant.count })
42
+ expect(subject.deny).to be_a(ErrorResponse)
43
+ end
45
44
  end
46
45
  end
47
46
  end
@@ -40,13 +40,28 @@ module Doorkeeper::OAuth::Helpers
40
40
  expect(URIChecker.valid?(uri)).to be_falsey
41
41
  end
42
42
 
43
+ it "is invalid if localhost is resolved as as scheme (no scheme specified)" do
44
+ uri = "localhost:8080"
45
+ expect(URIChecker.valid?(uri)).to be_falsey
46
+ end
47
+
48
+ it "is invalid if scheme is missing #2" do
49
+ uri = "app.co:80"
50
+ expect(URIChecker.valid?(uri)).to be_falsey
51
+ end
52
+
43
53
  it "is invalid if is not an uri" do
44
54
  uri = " "
45
55
  expect(URIChecker.valid?(uri)).to be_falsey
46
56
  end
47
57
 
48
- it "is valid for native uris" do
49
- uri = "urn:ietf:wg:oauth:2.0:oob"
58
+ it "is valid for custom schemes" do
59
+ uri = "com.example.app:/test"
60
+ expect(URIChecker.valid?(uri)).to be_truthy
61
+ end
62
+
63
+ it "is valid for custom schemes with authority marker (common misconfiguration)" do
64
+ uri = "com.example.app://test"
50
65
  expect(URIChecker.valid?(uri)).to be_truthy
51
66
  end
52
67
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ module Doorkeeper::OAuth
6
+ describe InvalidRequestResponse do
7
+ describe "#name" do
8
+ it { expect(subject.name).to eq(:invalid_request) }
9
+ end
10
+
11
+ describe "#status" do
12
+ it { expect(subject.status).to eq(:bad_request) }
13
+ end
14
+
15
+ describe :from_request do
16
+ let(:response) { InvalidRequestResponse.from_request(request) }
17
+
18
+ context "missing param" do
19
+ let(:request) { double(missing_param: "some_param") }
20
+
21
+ it "sets a description" do
22
+ expect(response.description).to eq(
23
+ I18n.t(:missing_param, scope: %i[doorkeeper errors messages invalid_request], value: "some_param")
24
+ )
25
+ end
26
+
27
+ it "sets the reason" do
28
+ expect(response.reason).to eq(:missing_param)
29
+ end
30
+ end
31
+
32
+ context "server doesn not support_pkce" do
33
+ let(:request) { double(invalid_request_reason: :not_support_pkce) }
34
+
35
+ it "sets a description" do
36
+ expect(response.description).to eq(
37
+ I18n.t(:not_support_pkce, scope: %i[doorkeeper errors messages invalid_request])
38
+ )
39
+ end
40
+
41
+ it "sets the reason" do
42
+ expect(response.reason).to eq(:not_support_pkce)
43
+ end
44
+ end
45
+
46
+ context "request is not authorized" do
47
+ let(:request) { double(invalid_request_reason: :request_not_authorized) }
48
+
49
+ it "sets a description" do
50
+ expect(response.description).to eq(
51
+ I18n.t(:request_not_authorized, scope: %i[doorkeeper errors messages invalid_request])
52
+ )
53
+ end
54
+
55
+ it "sets the reason" do
56
+ expect(response.reason).to eq(:request_not_authorized)
57
+ end
58
+ end
59
+
60
+ context "unknown reason" do
61
+ let(:request) { double(invalid_request_reason: :unknown_reason) }
62
+
63
+ it "sets a description" do
64
+ expect(response.description).to eq(
65
+ I18n.t(:unknown, scope: %i[doorkeeper errors messages invalid_request])
66
+ )
67
+ end
68
+
69
+ it "unknown reason" do
70
+ expect(response.reason).to eq(:unknown_reason)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end