rails_api_auth 0.0.2
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/LICENSE +22 -0
- data/README.md +3 -0
- data/Rakefile +20 -0
- data/app/controllers/oauth2_controller.rb +54 -0
- data/app/controllers/rails_api_auth/application_controller.rb +7 -0
- data/app/lib/login_not_found.rb +9 -0
- data/app/models/login.rb +47 -0
- data/app/services/facebook_authenticator.rb +64 -0
- data/config/initializers/facebook.rb +6 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20150709221755_create_logins.rb +16 -0
- data/lib/rails_api_auth.rb +5 -0
- data/lib/rails_api_auth/authentication.rb +32 -0
- data/lib/rails_api_auth/engine.rb +19 -0
- data/lib/rails_api_auth/version.rb +5 -0
- data/lib/tasks/rails_api_auth_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +7 -0
- data/spec/dummy/app/controllers/authenticated_controller.rb +13 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +18 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +38 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20150709221900_create_users.rb +11 -0
- data/spec/dummy/db/production.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +34 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +16 -0
- data/spec/dummy/log/test.log +8350 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/logins.rb +11 -0
- data/spec/models/login_spec.rb +69 -0
- data/spec/requests/authenticated_spec.rb +47 -0
- data/spec/requests/oauth2_spec.rb +187 -0
- data/spec/services/facebook_authenticator_spec.rb +54 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/factory_girl.rb +3 -0
- metadata +233 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/404.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
62
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/422.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The change you wanted was rejected.</h1>
|
62
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/500.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>We're sorry, but something went wrong.</h1>
|
62
|
+
</div>
|
63
|
+
<p>If you are the application owner check the logs for more information.</p>
|
64
|
+
</div>
|
65
|
+
</body>
|
66
|
+
</html>
|
File without changes
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Login do
|
4
|
+
it { is_expected.to validate_presence_of(:email) }
|
5
|
+
it { is_expected.to allow_value('test@example.com').for(:email) }
|
6
|
+
it { is_expected.to_not allow_value('test_example.com').for(:email) }
|
7
|
+
|
8
|
+
it 'validates presence of either password or Facebook UID' do
|
9
|
+
login = described_class.new(email: 'test@example.com', oauth2_token: 'token')
|
10
|
+
|
11
|
+
expect(login).to_not be_valid
|
12
|
+
end
|
13
|
+
|
14
|
+
it "doesn't validate presence of password when Facebook UID is present" do
|
15
|
+
login = described_class.new(email: 'test@example.com', oauth2_token: 'token', facebook_uid: '123')
|
16
|
+
|
17
|
+
expect(login).to be_valid
|
18
|
+
end
|
19
|
+
|
20
|
+
it "doesn't validate presence of Facebook UID when password is present" do
|
21
|
+
login = described_class.new(email: 'test@example.com', oauth2_token: 'token', password: '123')
|
22
|
+
|
23
|
+
expect(login).to be_valid
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#refresh_oauth2_token!' do
|
27
|
+
subject { described_class.new(oauth2_token: 'oldtoken') }
|
28
|
+
|
29
|
+
before do
|
30
|
+
allow(subject).to receive(:save!)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'force-resets the oauth2 token' do
|
34
|
+
expect { subject.refresh_oauth2_token! }.to change(subject, :oauth2_token)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'saves the model' do
|
38
|
+
expect(subject).to receive(:save!)
|
39
|
+
|
40
|
+
subject.refresh_oauth2_token!
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#consume_single_use_oauth2_token!' do
|
45
|
+
subject { described_class.new(single_use_oauth2_token: 'token') }
|
46
|
+
|
47
|
+
before do
|
48
|
+
allow(subject).to receive(:save!)
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when the supplied token is valid' do
|
52
|
+
it 'resets the single use oauth2 token' do
|
53
|
+
expect { subject.consume_single_use_oauth2_token!(subject.single_use_oauth2_token) }.to change(subject, :single_use_oauth2_token)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'saves the model' do
|
57
|
+
expect(subject).to receive(:save!)
|
58
|
+
|
59
|
+
subject.refresh_oauth2_token!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when the supplied token is invalid' do
|
64
|
+
it 'raises an InvalidSingleUseOAuth2Token' do
|
65
|
+
expect { subject.consume_single_use_oauth2_token!('invalid token') }.to raise_error(Login::InvalidSingleUseOAuth2Token)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Authenticated route' do
|
4
|
+
let!(:login) { create(:login) }
|
5
|
+
let(:headers) do
|
6
|
+
{
|
7
|
+
'Authorization': "Bearer #{login.oauth2_token}"
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { get '/authenticated', {}, headers }
|
12
|
+
|
13
|
+
it 'assigns login found to @current_login' do
|
14
|
+
subject
|
15
|
+
|
16
|
+
assigns[:current_login] = login
|
17
|
+
end
|
18
|
+
|
19
|
+
it '200' do
|
20
|
+
subject
|
21
|
+
|
22
|
+
expect(response.status).to eq 200
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'lets the action get rendered' do
|
26
|
+
subject
|
27
|
+
|
28
|
+
expect(response.body).to eql 'zuper content'
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'no token' do
|
32
|
+
|
33
|
+
subject { get '/authenticated' }
|
34
|
+
|
35
|
+
it '401' do
|
36
|
+
subject
|
37
|
+
|
38
|
+
expect(response.status).to eq 401
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'responds with an empty body' do
|
42
|
+
subject
|
43
|
+
|
44
|
+
expect(response.body).to be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Oauth2 API' do
|
4
|
+
|
5
|
+
let!(:login) { create(:login) }
|
6
|
+
|
7
|
+
describe 'POST /token' do
|
8
|
+
let(:params) { { grant_type: 'password', username: login.email, password: login.password } }
|
9
|
+
|
10
|
+
subject { post '/token', params }
|
11
|
+
|
12
|
+
context 'for grant_type "password"' do
|
13
|
+
context 'with valid login credentials' do
|
14
|
+
it 'succeeds' do
|
15
|
+
subject
|
16
|
+
|
17
|
+
expect(response).to have_http_status(200)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'responds with an access token' do
|
21
|
+
subject
|
22
|
+
|
23
|
+
expect(response.body).to be_json_eql({ access_token: login.oauth2_token }.to_json)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with invalid login credentials' do
|
28
|
+
let(:params) { { grant_type: 'password', username: 'bad@email.com', password: 'badpassword' } }
|
29
|
+
|
30
|
+
it 'responds with status 400' do
|
31
|
+
subject
|
32
|
+
|
33
|
+
expect(response).to have_http_status(400)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'responds with an invalid grant error' do
|
37
|
+
subject
|
38
|
+
|
39
|
+
expect(response.body).to be_json_eql({ error: 'invalid_grant' }.to_json)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'for grant_type "facebook_auth_code"' do
|
45
|
+
let(:secret) { described_class::FB_APP_SECRET }
|
46
|
+
let(:params) { { grant_type: 'facebook_auth_code', auth_code: 'fb auth code' } }
|
47
|
+
let(:facebook_email) { login.email }
|
48
|
+
let(:facebook_data) do
|
49
|
+
{
|
50
|
+
id: '1238190321',
|
51
|
+
email: facebook_email
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
before do
|
56
|
+
stub_request(:get, %r{https://graph.facebook.com/v2.3/oauth/access_token}).to_return(body: '{ "access_token": "access_token" }')
|
57
|
+
stub_request(:get, %r{https://graph.facebook.com/v2.3/me}).to_return(body: JSON.generate(facebook_data), headers: { 'Content-Type' => 'application/json' })
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when a login with the posted Facebook email exists' do
|
61
|
+
it 'connects the login to the Facebook account' do
|
62
|
+
subject
|
63
|
+
|
64
|
+
expect(login.reload.facebook_uid).to eq(facebook_data[:id])
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'succeeds' do
|
68
|
+
subject
|
69
|
+
|
70
|
+
expect(response).to have_http_status(200)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'responds with an oauth2 token' do
|
74
|
+
subject
|
75
|
+
|
76
|
+
expect(response.body).to be_json_eql({ access_token: login.oauth2_token }.to_json)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when no login with the posted Facebook email exists' do
|
81
|
+
let(:facebook_email) { Faker::Internet.email }
|
82
|
+
|
83
|
+
it 'succeeds' do
|
84
|
+
subject
|
85
|
+
|
86
|
+
expect(response).to have_http_status(200)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'creates a login with it' do
|
90
|
+
expect { subject }.to change { Login.where(email: facebook_email).count }.by(1)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'responds with an oauth2 token' do
|
94
|
+
subject
|
95
|
+
login = Login.find_by(email: facebook_email)
|
96
|
+
|
97
|
+
expect(response.body).to be_json_eql({ access_token: login.oauth2_token }.to_json)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when no facebook code is sent' do
|
102
|
+
let(:params) { { grant_type: 'facebook_auth_code' } }
|
103
|
+
|
104
|
+
it 'responds with status 400' do
|
105
|
+
subject
|
106
|
+
|
107
|
+
expect(response).to have_http_status(400)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'responds with a no authorization code error' do
|
111
|
+
subject
|
112
|
+
|
113
|
+
expect(response.body).to be_json_eql({ error: 'no_authorization_code' }.to_json)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when Facebook responds with an error' do
|
118
|
+
before do
|
119
|
+
stub_request(:get, %r{https://graph.facebook.com/v2.3/oauth/access_token}).to_return(status: 422)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'responds with status 500' do
|
123
|
+
subject
|
124
|
+
|
125
|
+
expect(response).to have_http_status(500)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'responds with an empty response body' do
|
129
|
+
subject
|
130
|
+
|
131
|
+
expect(response.body).to eql('')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'for an unknown grant type' do
|
137
|
+
let(:params) { { grant_type: 'UNKNOWN' } }
|
138
|
+
|
139
|
+
it 'responds with status 400' do
|
140
|
+
subject
|
141
|
+
|
142
|
+
expect(response).to have_http_status(400)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'responds with an invalid grant error' do
|
146
|
+
subject
|
147
|
+
|
148
|
+
expect(response.body).to be_json_eql({ error: 'unsupported_grant_type' }.to_json)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe 'POST #destroy' do
|
154
|
+
let(:params) { { token_type_hint: 'access_token', token: login.oauth2_token } }
|
155
|
+
|
156
|
+
subject { post '/revoke', params }
|
157
|
+
|
158
|
+
it 'succeeds' do
|
159
|
+
subject
|
160
|
+
|
161
|
+
expect(response).to have_http_status(200)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'resets login token' do
|
165
|
+
expect { subject }.to change { login.reload.oauth2_token }
|
166
|
+
|
167
|
+
subject
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'for an unknown (or stale) token' do
|
171
|
+
let(:params) { { token_type_hint: 'access_token', token: 'badtoken' } }
|
172
|
+
|
173
|
+
it 'succeeds' do
|
174
|
+
subject
|
175
|
+
|
176
|
+
expect(response).to have_http_status(200)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "doesn't reset any logins' token" do
|
180
|
+
|
181
|
+
expect_any_instance_of(LoginNotFound).to receive(:refresh_oauth2_token!)
|
182
|
+
|
183
|
+
subject
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|