simple_oauth2 0.0.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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +25 -0
  3. data/.coveralls.yml +1 -0
  4. data/.gitignore +26 -0
  5. data/.hound.yml +4 -0
  6. data/.rubocop.yml +5 -0
  7. data/.rubocop_todo.yml +12 -0
  8. data/.travis.yml +31 -0
  9. data/Gemfile +18 -0
  10. data/LICENSE +21 -0
  11. data/README.md +11 -0
  12. data/Rakefile +11 -0
  13. data/gemfiles/nobrainer.rb +15 -0
  14. data/lib/simple_oauth2/configuration/class_accessors.rb +36 -0
  15. data/lib/simple_oauth2/configuration/constants.rb +36 -0
  16. data/lib/simple_oauth2/configuration.rb +169 -0
  17. data/lib/simple_oauth2/generators/authorization.rb +64 -0
  18. data/lib/simple_oauth2/generators/base.rb +31 -0
  19. data/lib/simple_oauth2/generators/token.rb +71 -0
  20. data/lib/simple_oauth2/helpers.rb +40 -0
  21. data/lib/simple_oauth2/mixins/nobrainer/access_grant.rb +62 -0
  22. data/lib/simple_oauth2/mixins/nobrainer/access_token.rb +98 -0
  23. data/lib/simple_oauth2/mixins/nobrainer/client.rb +43 -0
  24. data/lib/simple_oauth2/resource/bearer.rb +20 -0
  25. data/lib/simple_oauth2/responses.rb +62 -0
  26. data/lib/simple_oauth2/scopes.rb +59 -0
  27. data/lib/simple_oauth2/strategies/authorization_code.rb +22 -0
  28. data/lib/simple_oauth2/strategies/base.rb +61 -0
  29. data/lib/simple_oauth2/strategies/client_credentials.rb +21 -0
  30. data/lib/simple_oauth2/strategies/code.rb +25 -0
  31. data/lib/simple_oauth2/strategies/password.rb +21 -0
  32. data/lib/simple_oauth2/strategies/refresh_token.rb +53 -0
  33. data/lib/simple_oauth2/strategies/token.rb +24 -0
  34. data/lib/simple_oauth2/uniq_token.rb +20 -0
  35. data/lib/simple_oauth2/version.rb +26 -0
  36. data/lib/simple_oauth2.rb +62 -0
  37. data/logo.png +0 -0
  38. data/simple_oauth2.gemspec +22 -0
  39. data/spec/configuration/config_spec.rb +181 -0
  40. data/spec/configuration/version_spec.rb +11 -0
  41. data/spec/dummy/endpoints/authorization.rb +15 -0
  42. data/spec/dummy/endpoints/custom_authorization.rb +21 -0
  43. data/spec/dummy/endpoints/custom_token.rb +21 -0
  44. data/spec/dummy/endpoints/status.rb +51 -0
  45. data/spec/dummy/endpoints/token.rb +22 -0
  46. data/spec/dummy/orm/nobrainer/app/config/db.rb +8 -0
  47. data/spec/dummy/orm/nobrainer/app/models/access_grant.rb +3 -0
  48. data/spec/dummy/orm/nobrainer/app/models/access_token.rb +3 -0
  49. data/spec/dummy/orm/nobrainer/app/models/client.rb +3 -0
  50. data/spec/dummy/orm/nobrainer/app/models/user.rb +11 -0
  51. data/spec/dummy/orm/nobrainer/app/twitter.rb +51 -0
  52. data/spec/dummy/orm/nobrainer/config.ru +37 -0
  53. data/spec/dummy/simple_oauth2_config.rb +7 -0
  54. data/spec/requests/flows/authorization_code_spec.rb +177 -0
  55. data/spec/requests/flows/client_credentials_spec.rb +163 -0
  56. data/spec/requests/flows/code_spec.rb +98 -0
  57. data/spec/requests/flows/password_spec.rb +183 -0
  58. data/spec/requests/flows/refresh_token_spec.rb +282 -0
  59. data/spec/requests/flows/token_spec.rb +113 -0
  60. data/spec/requests/protected_resources_spec.rb +65 -0
  61. data/spec/requests/revoke_token_spec.rb +90 -0
  62. data/spec/spec_helper.rb +51 -0
  63. data/spec/support/helper.rb +11 -0
  64. metadata +125 -0
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Token Endpoint' do
4
+ subject { -> { post url, params } }
5
+
6
+ let(:url) { '/oauth/token' }
7
+ let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
8
+ let(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
9
+ let(:grant_type) { 'authorization_code' }
10
+ let(:client_id) { client.key }
11
+ let(:client_secret) { client.secret }
12
+ let(:scopes) { nil }
13
+ let(:redirect_uri) { 'localhost:3000/home' }
14
+ let(:another_redirect_uri) { redirect_uri }
15
+ let(:access_grant) { AccessGrant.create_for(client, user, redirect_uri, scopes) }
16
+ let(:code) { access_grant.token }
17
+ let(:params) do
18
+ {
19
+ code: code,
20
+ redirect_uri: another_redirect_uri,
21
+ client_id: client_id,
22
+ client_secret: client_secret,
23
+ grant_type: grant_type
24
+ }
25
+ end
26
+
27
+ describe 'POST /oauth/custom_token' do
28
+ let(:url) { '/oauth/custom_token' }
29
+ before { subject.call }
30
+
31
+ context 'invokes custom block' do
32
+ it { expect(last_response.status).to eq(400) }
33
+ end
34
+ end
35
+
36
+ describe 'POST /oauth/token' do
37
+ describe 'AuthorizationCode flow' do
38
+ before { subject.call }
39
+
40
+ context 'when valid params' do
41
+ it { expect(AccessToken.count).to eq 1 }
42
+ it { expect(last_response.status).to eq 200 }
43
+ it { expect(json_body[:access_token]).not_to be_nil }
44
+ it { expect(json_body[:token_type]).to eq 'bearer' }
45
+ it { expect(json_body[:expires_in]).to eq 7200 }
46
+ end
47
+
48
+ context 'when invalid params' do
49
+ context 'without code' do
50
+ let(:code) {}
51
+
52
+ it { expect(AccessToken.count).to be_zero }
53
+ it { expect(json_body[:error]).to eq('invalid_request') }
54
+ it { expect(json_body[:error_description]).to eq("'code' required.") }
55
+ it { expect(last_response.status).to eq 400 }
56
+ end
57
+
58
+ context 'with invalid code' do
59
+ let(:code) { 'invalid' }
60
+ let(:error_description) do
61
+ 'The provided access grant is invalid, expired, or revoked '\
62
+ '(e.g. invalid assertion, expired authorization token, '\
63
+ 'bad end-user password credentials, or mismatching authorization code and redirection URI).'
64
+ end
65
+
66
+ it { expect(AccessToken.count).to be_zero }
67
+ it { expect(json_body[:error]).to eq('invalid_grant') }
68
+ it { expect(json_body[:error_description]).to eq(error_description) }
69
+ it { expect(last_response.status).to eq 400 }
70
+ end
71
+
72
+ context 'without redirect_uri' do
73
+ let(:redirect_uri) {}
74
+ let(:error_description) do
75
+ 'The provided access grant is invalid, expired, or revoked '\
76
+ '(e.g. invalid assertion, expired authorization token, '\
77
+ 'bad end-user password credentials, or mismatching authorization code and redirection URI).'
78
+ end
79
+
80
+ it { expect(AccessToken.count).to be_zero }
81
+ it { expect(json_body[:error]).to eq('invalid_grant') }
82
+ it { expect(json_body[:error_description]).to eq(error_description) }
83
+ it { expect(last_response.status).to eq 400 }
84
+ end
85
+
86
+ context 'with invalid redirect_uri' do
87
+ let(:another_redirect_uri) { 'invalid' }
88
+
89
+ let(:error_description) do
90
+ 'The provided access grant is invalid, expired, or revoked '\
91
+ '(e.g. invalid assertion, expired authorization token, '\
92
+ 'bad end-user password credentials, or mismatching authorization code and redirection URI).'
93
+ end
94
+
95
+ it { expect(AccessToken.count).to be_zero }
96
+ it { expect(json_body[:error]).to eq('invalid_grant') }
97
+ it { expect(json_body[:error_description]).to eq(error_description) }
98
+ it { expect(last_response.status).to eq 400 }
99
+ end
100
+
101
+ context 'without client_id' do
102
+ let(:client_id) {}
103
+
104
+ it { expect(AccessToken.count).to be_zero }
105
+ it { expect(json_body[:error]).to eq('invalid_request') }
106
+ it { expect(json_body[:error_description]).to eq("'client_id' required.") }
107
+ it { expect(last_response.status).to eq 400 }
108
+ end
109
+
110
+ context 'with invalid client_id' do
111
+ let(:client_id) { 'invalid' }
112
+ let(:error_description) do
113
+ 'The client identifier provided is invalid, the client failed to authenticate, '\
114
+ 'the client did not include its credentials, provided multiple client credentials, '\
115
+ 'or used unsupported credentials type.'
116
+ end
117
+
118
+ it { expect(AccessToken.count).to be_zero }
119
+ it { expect(json_body[:error]).to eq('invalid_client') }
120
+ it { expect(json_body[:error_description]).to eq(error_description) }
121
+ it { expect(last_response.status).to eq 401 }
122
+ end
123
+
124
+ context 'without client_secret' do
125
+ let(:client_secret) {}
126
+ let(:error_description) do
127
+ 'The client identifier provided is invalid, the client failed to authenticate, '\
128
+ 'the client did not include its credentials, provided multiple client credentials, '\
129
+ 'or used unsupported credentials type.'
130
+ end
131
+
132
+ it { expect(AccessToken.count).to be_zero }
133
+ it { expect(json_body[:error]).to eq('invalid_client') }
134
+ it { expect(json_body[:error_description]).to eq(error_description) }
135
+ it { expect(last_response.status).to eq 401 }
136
+ end
137
+
138
+ context 'with invalid client_secret' do
139
+ let(:client_secret) { 'invalid' }
140
+ let(:error_description) do
141
+ 'The client identifier provided is invalid, the client failed to authenticate, '\
142
+ 'the client did not include its credentials, provided multiple client credentials, '\
143
+ 'or used unsupported credentials type.'
144
+ end
145
+
146
+ it { expect(AccessToken.count).to be_zero }
147
+ it { expect(json_body[:error]).to eq('invalid_client') }
148
+ it { expect(json_body[:error_description]).to eq(error_description) }
149
+ it { expect(last_response.status).to eq 401 }
150
+ end
151
+
152
+ context 'without grant_type' do
153
+ let(:grant_type) {}
154
+
155
+ it { expect(AccessToken.count).to be_zero }
156
+ it { expect(json_body[:error]).to eq('invalid_request') }
157
+ it { expect(json_body[:error_description]).to eq("'grant_type' required.") }
158
+ it { expect(last_response.status).to eq 400 }
159
+ end
160
+
161
+ context 'with invalid grant_type' do
162
+ let(:grant_type) { 'invalid' }
163
+ let(:error_description) do
164
+ 'The access grant included - '\
165
+ 'its type or another attribute - '\
166
+ 'is not supported by the authorization server.'
167
+ end
168
+
169
+ it { expect(AccessToken.count).to be_zero }
170
+ it { expect(json_body[:error]).to eq('unsupported_grant_type') }
171
+ it { expect(json_body[:error_description]).to eq(error_description) }
172
+ it { expect(last_response.status).to eq 400 }
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,163 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Token Endpoint' do
4
+ subject { -> { post url, params } }
5
+
6
+ let(:url) { '/oauth/token' }
7
+ let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
8
+ let(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
9
+ let(:grant_type) { 'client_credentials' }
10
+ let(:scopes) { 'read,write' }
11
+ let(:username) { user.username }
12
+ let(:password) { user.encrypted_password }
13
+ let(:client_id) { client.key }
14
+ let(:params) do
15
+ {
16
+ username: username,
17
+ password: password,
18
+ client_id: client_id,
19
+ grant_type: grant_type,
20
+ scope: scopes
21
+ }
22
+ end
23
+
24
+ describe 'POST /oauth/token' do
25
+ describe 'ClientCredentials flow' do
26
+ before { subject.call }
27
+
28
+ context 'when valid params' do
29
+ context 'return AccessToken' do
30
+ it { expect(AccessToken.count).to eq 1 }
31
+ it { expect(AccessToken.first.client_id).to eq(client.id) }
32
+ it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
33
+
34
+ it { expect(last_response.status).to eq 200 }
35
+ it { expect(json_body[:access_token]).to be_present }
36
+ it { expect(json_body[:token_type]).to eq 'bearer' }
37
+ it { expect(json_body[:expires_in]).to eq 7200 }
38
+ it { expect(json_body[:refresh_token]).to be_nil }
39
+ it { expect(json_body[:scope]).to eq('read,write') }
40
+ end
41
+
42
+ context 'return AccessToken without scopes' do
43
+ let(:scopes) {}
44
+
45
+ it { expect(AccessToken.count).to eq 1 }
46
+ it { expect(AccessToken.first.client_id).to eq(client.id) }
47
+ it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
48
+
49
+ it { expect(last_response.status).to eq 200 }
50
+ it { expect(json_body[:access_token]).to be_present }
51
+ it { expect(json_body[:token_type]).to eq 'bearer' }
52
+ it { expect(json_body[:expires_in]).to eq 7200 }
53
+ it { expect(json_body[:refresh_token]).to be_nil }
54
+ it { expect(json_body[:scope]).to be_nil }
55
+ end
56
+ end
57
+
58
+ context 'when invalid params' do
59
+ context 'without username' do
60
+ let(:username) {}
61
+ let(:error_description) do
62
+ 'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
63
+ 'expired authorization token, bad end-user password credentials, '\
64
+ 'or mismatching authorization code and redirection URI).'
65
+ end
66
+
67
+ it { expect(AccessToken.count).to be_zero }
68
+ it { expect(json_body[:error]).to eq('invalid_grant') }
69
+ it { expect(json_body[:error_description]).to eq error_description }
70
+ it { expect(last_response.status).to eq 400 }
71
+ end
72
+
73
+ context 'with invalid username' do
74
+ let(:username) { 'invalid@example.com' }
75
+ let(:error_description) do
76
+ 'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
77
+ 'expired authorization token, bad end-user password credentials, '\
78
+ 'or mismatching authorization code and redirection URI).'
79
+ end
80
+
81
+ it { expect(AccessToken.count).to be_zero }
82
+ it { expect(json_body[:error]).to eq('invalid_grant') }
83
+ it { expect(json_body[:error_description]).to eq(error_description) }
84
+ it { expect(last_response.status).to eq 400 }
85
+ end
86
+
87
+ context 'without password' do
88
+ let(:password) {}
89
+ let(:error_description) do
90
+ 'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
91
+ 'expired authorization token, bad end-user password credentials, '\
92
+ 'or mismatching authorization code and redirection URI).'
93
+ end
94
+
95
+ it { expect(AccessToken.count).to be_zero }
96
+ it { expect(json_body[:error]).to eq('invalid_grant') }
97
+ it { expect(json_body[:error_description]).to eq error_description }
98
+ it { expect(last_response.status).to eq 400 }
99
+ end
100
+
101
+ context 'with invalid params' do
102
+ let(:password) { 'invalid@password.com' }
103
+ let(:error_description) do
104
+ 'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
105
+ 'expired authorization token, bad end-user password credentials, '\
106
+ 'or mismatching authorization code and redirection URI).'
107
+ end
108
+
109
+ it { expect(AccessToken.count).to be_zero }
110
+ it { expect(json_body[:error]).to eq('invalid_grant') }
111
+ it { expect(json_body[:error_description]).to eq(error_description) }
112
+ it { expect(last_response.status).to eq 400 }
113
+ end
114
+
115
+ context 'without client_id' do
116
+ let(:client_id) {}
117
+
118
+ it { expect(AccessToken.count).to be_zero }
119
+ it { expect(json_body[:error]).to eq('invalid_request') }
120
+ it { expect(json_body[:error_description]).to eq("'client_id' required.") }
121
+ it { expect(last_response.status).to eq 400 }
122
+ end
123
+
124
+ context 'with invalid client_id' do
125
+ let(:client_id) { 'invalid' }
126
+ let(:error_description) do
127
+ 'The client identifier provided is invalid, the client failed to authenticate, '\
128
+ 'the client did not include its credentials, provided multiple client credentials, '\
129
+ 'or used unsupported credentials type.'
130
+ end
131
+
132
+ it { expect(AccessToken.count).to be_zero }
133
+ it { expect(json_body[:error]).to eq('invalid_client') }
134
+ it { expect(json_body[:error_description]).to eq(error_description) }
135
+ it { expect(last_response.status).to eq 401 }
136
+ end
137
+
138
+ context 'without grant_type' do
139
+ let(:grant_type) {}
140
+
141
+ it { expect(AccessToken.count).to be_zero }
142
+ it { expect(json_body[:error]).to eq('invalid_request') }
143
+ it { expect(json_body[:error_description]).to eq("'grant_type' required.") }
144
+ it { expect(last_response.status).to eq 400 }
145
+ end
146
+
147
+ context 'with invalid grant_type' do
148
+ let(:grant_type) { 'invalid' }
149
+ let(:error_description) do
150
+ 'The access grant included - '\
151
+ 'its type or another attribute - '\
152
+ 'is not supported by the authorization server.'
153
+ end
154
+
155
+ it { expect(AccessToken.count).to be_zero }
156
+ it { expect(json_body[:error]).to eq('unsupported_grant_type') }
157
+ it { expect(json_body[:error_description]).to eq(error_description) }
158
+ it { expect(last_response.status).to eq 400 }
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Authorization Endpoint' do
4
+ subject { -> { post url, params } }
5
+
6
+ let(:url) { '/oauth/authorization' }
7
+ let!(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
8
+ let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
9
+ let(:client_id) { client.key }
10
+ let(:redirect_uri) { client.redirect_uri }
11
+ let(:response_type) { 'code' }
12
+ let(:state) { nil }
13
+ let(:scope) { nil }
14
+ let(:params) do
15
+ {
16
+ client_id: client_id,
17
+ redirect_uri: redirect_uri,
18
+ response_type: response_type,
19
+ state: state,
20
+ scope: scope
21
+ }
22
+ end
23
+
24
+ describe 'POST /oauth/authorization' do
25
+ describe 'Code flow' do
26
+ before { subject.call }
27
+
28
+ context 'when valid params' do
29
+ let(:response_header) { "#{client.redirect_uri}?code=#{AccessGrant.last.token}" }
30
+
31
+ it { expect(AccessGrant.count).to eq 1 }
32
+ it { expect(AccessGrant.last.scopes).to be_empty }
33
+ it { expect(AccessGrant.last.resource_owner.username).to eq user.username }
34
+ it { expect(last_response.status).to eq 302 }
35
+ it { expect(last_response.headers['Location']).to eq response_header }
36
+
37
+ context 'without redirect_uri' do
38
+ let(:redirect_uri) {}
39
+
40
+ it { expect(last_response.headers['Location']).to eq response_header }
41
+ end
42
+
43
+ context 'with state' do
44
+ let(:state) { 'zxc' }
45
+ let(:response_header_with_state) { "#{client.redirect_uri}?code=#{AccessGrant.last.token}&state=#{state}" }
46
+
47
+ it { expect(last_response.headers['Location']).to eq response_header_with_state }
48
+ end
49
+
50
+ context 'with scopes' do
51
+ let(:scope) { 'read,write' }
52
+
53
+ it { expect(AccessGrant.last.scopes).to eq 'read,write' }
54
+ end
55
+ end
56
+
57
+ context 'when invalid params' do
58
+ context 'without client_id' do
59
+ let(:client_id) {}
60
+
61
+ it { expect(last_response.status).to eq 400 }
62
+ it { expect(json_body[:error]).to eq('bad_request') }
63
+ end
64
+
65
+ context 'with invalid client_id' do
66
+ let(:client_id) { 'invalid' }
67
+
68
+ it { expect(last_response.status).to eq 400 }
69
+ it { expect(json_body[:error]).to eq('bad_request') }
70
+ end
71
+
72
+ context 'with invalid redirect_uri' do
73
+ let(:redirect_uri) { 'invalid' }
74
+
75
+ it { expect(last_response.status).to eq 400 }
76
+ it { expect(json_body[:error]).to eq('bad_request') }
77
+ end
78
+
79
+ context 'without response_type' do
80
+ let(:response_type) {}
81
+
82
+ it { expect(last_response.status).to eq 400 }
83
+ it { expect(json_body[:error]).to eq('invalid_request') }
84
+ it { expect(json_body[:error_description]).to eq "'response_type' required." }
85
+ end
86
+
87
+ context 'with invalid response_type' do
88
+ let(:response_type) { 'invalid' }
89
+ let(:error_description) { 'The requested response type is not supported by the authorization server.' }
90
+
91
+ it { expect(last_response.status).to eq 400 }
92
+ it { expect(json_body[:error]).to eq 'unsupported_response_type' }
93
+ it { expect(json_body[:error_description]).to eq error_description }
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,183 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Token Endpoint' do
4
+ subject { -> { post url, params } }
5
+
6
+ let(:url) { '/oauth/token' }
7
+ let(:client) { Client.create(name: FFaker::Internet.domain_word, redirect_uri: 'http://localhost:3000/home') }
8
+ let(:user) { User.create(username: FFaker::Internet.user_name, encrypted_password: FFaker::Internet.password) }
9
+ let(:grant_type) { 'password' }
10
+ let(:scopes) { 'read,write' }
11
+ let(:username) { user.username }
12
+ let(:password) { user.encrypted_password }
13
+ let(:client_id) { client.key }
14
+ let(:client_secret) { client.secret }
15
+ let(:params) do
16
+ {
17
+ username: username,
18
+ password: password,
19
+ client_id: client_id,
20
+ client_secret: client_secret,
21
+ grant_type: grant_type,
22
+ scope: scopes
23
+ }
24
+ end
25
+
26
+ describe 'POST /oauth/token' do
27
+ describe 'Password flow' do
28
+ before { subject.call }
29
+
30
+ context 'when invalid params' do
31
+ context 'without username' do
32
+ let(:username) {}
33
+
34
+ it { expect(AccessToken.count).to be_zero }
35
+ it { expect(json_body[:error]).to eq('invalid_request') }
36
+ it { expect(json_body[:error_description]).to eq("'username' required.") }
37
+ it { expect(last_response.status).to eq 400 }
38
+ end
39
+
40
+ context 'with invalid username' do
41
+ let(:username) { 'invalid@example.com' }
42
+ let(:error_description) do
43
+ 'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
44
+ 'expired authorization token, bad end-user password credentials, '\
45
+ 'or mismatching authorization code and redirection URI).'
46
+ end
47
+
48
+ it { expect(AccessToken.count).to be_zero }
49
+ it { expect(json_body[:error]).to eq('invalid_grant') }
50
+ it { expect(json_body[:error_description]).to eq(error_description) }
51
+ it { expect(last_response.status).to eq 400 }
52
+ end
53
+
54
+ context 'without password' do
55
+ let(:password) {}
56
+
57
+ it { expect(AccessToken.count).to be_zero }
58
+ it { expect(json_body[:error]).to eq('invalid_request') }
59
+ it { expect(json_body[:error_description]).to eq("'password' required.") }
60
+ it { expect(last_response.status).to eq 400 }
61
+ end
62
+
63
+ context 'with invalid password' do
64
+ let(:password) { 'invalid@password.com' }
65
+ let(:error_description) do
66
+ 'The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, '\
67
+ 'expired authorization token, bad end-user password credentials, '\
68
+ 'or mismatching authorization code and redirection URI).'
69
+ end
70
+
71
+ it { expect(AccessToken.count).to be_zero }
72
+ it { expect(json_body[:error]).to eq('invalid_grant') }
73
+ it { expect(json_body[:error_description]).to eq(error_description) }
74
+ it { expect(last_response.status).to eq 400 }
75
+ end
76
+
77
+ context 'without client_id' do
78
+ let(:client_id) {}
79
+
80
+ it { expect(AccessToken.count).to be_zero }
81
+ it { expect(json_body[:error]).to eq('invalid_request') }
82
+ it { expect(json_body[:error_description]).to eq("'client_id' required.") }
83
+ it { expect(last_response.status).to eq 400 }
84
+ end
85
+
86
+ context 'with invalid client_id' do
87
+ let(:client_id) { 'invalid' }
88
+ let(:error_description) do
89
+ 'The client identifier provided is invalid, the client failed to authenticate, '\
90
+ 'the client did not include its credentials, provided multiple client credentials, '\
91
+ 'or used unsupported credentials type.'
92
+ end
93
+
94
+ it { expect(AccessToken.count).to be_zero }
95
+ it { expect(json_body[:error]).to eq('invalid_client') }
96
+ it { expect(json_body[:error_description]).to eq(error_description) }
97
+ it { expect(last_response.status).to eq 401 }
98
+ end
99
+
100
+ context 'without client_secret' do
101
+ let(:client_secret) {}
102
+ let(:error_description) do
103
+ 'The client identifier provided is invalid, the client failed to authenticate, '\
104
+ 'the client did not include its credentials, provided multiple client credentials, '\
105
+ 'or used unsupported credentials type.'
106
+ end
107
+
108
+ it { expect(AccessToken.count).to be_zero }
109
+ it { expect(json_body[:error]).to eq('invalid_client') }
110
+ it { expect(json_body[:error_description]).to eq(error_description) }
111
+ it { expect(last_response.status).to eq 401 }
112
+ end
113
+
114
+ context 'with invalid client_secret' do
115
+ let(:client_secret) { 'invalid' }
116
+ let(:error_description) do
117
+ 'The client identifier provided is invalid, the client failed to authenticate, '\
118
+ 'the client did not include its credentials, provided multiple client credentials, '\
119
+ 'or used unsupported credentials type.'
120
+ end
121
+
122
+ it { expect(AccessToken.count).to be_zero }
123
+ it { expect(json_body[:error]).to eq('invalid_client') }
124
+ it { expect(json_body[:error_description]).to eq(error_description) }
125
+ it { expect(last_response.status).to eq 401 }
126
+ end
127
+
128
+ context 'without grant_type' do
129
+ let(:grant_type) {}
130
+
131
+ it { expect(AccessToken.count).to be_zero }
132
+ it { expect(json_body[:error]).to eq('invalid_request') }
133
+ it { expect(json_body[:error_description]).to eq("'grant_type' required.") }
134
+ it { expect(last_response.status).to eq 400 }
135
+ end
136
+
137
+ context 'with invalid grant_type' do
138
+ let(:grant_type) { 'invalid' }
139
+ let(:error_description) do
140
+ 'The access grant included - '\
141
+ 'its type or another attribute - '\
142
+ 'is not supported by the authorization server.'
143
+ end
144
+
145
+ it { expect(AccessToken.count).to be_zero }
146
+ it { expect(json_body[:error]).to eq('unsupported_grant_type') }
147
+ it { expect(json_body[:error_description]).to eq(error_description) }
148
+ it { expect(last_response.status).to eq 400 }
149
+ end
150
+ end
151
+
152
+ context 'when valid params' do
153
+ context 'return AccessToken' do
154
+ it { expect(AccessToken.count).to eq 1 }
155
+ it { expect(AccessToken.first.client_id).to eq(client.id) }
156
+ it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
157
+
158
+ it { expect(last_response.status).to eq 200 }
159
+ it { expect(json_body[:access_token]).to be_present }
160
+ it { expect(json_body[:token_type]).to eq 'bearer' }
161
+ it { expect(json_body[:expires_in]).to eq 7200 }
162
+ it { expect(json_body[:refresh_token]).to be_nil }
163
+ it { expect(json_body[:scope]).to eq('read,write') }
164
+ end
165
+
166
+ context 'return AccessToken without scopes' do
167
+ let(:scopes) {}
168
+
169
+ it { expect(AccessToken.count).to eq 1 }
170
+ it { expect(AccessToken.first.client_id).to eq(client.id) }
171
+ it { expect(AccessToken.first.resource_owner_id).to eq(user.id) }
172
+
173
+ it { expect(last_response.status).to eq 200 }
174
+ it { expect(json_body[:access_token]).to be_present }
175
+ it { expect(json_body[:token_type]).to eq 'bearer' }
176
+ it { expect(json_body[:expires_in]).to eq 7200 }
177
+ it { expect(json_body[:refresh_token]).to be_nil }
178
+ it { expect(json_body[:scope]).to be_nil }
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end