Commit f9f1a74

mo <mo.khan@gmail.com>
2018-09-09 18:43:23
exclude inactive tokens.
1 parent 90deb0b
Changed files (4)
app/controllers/oauths_controller.rb
@@ -22,7 +22,7 @@ class OauthsController < ApplicationController
     response.headers['Cache-Control'] = 'no-store'
     response.headers['Pragma'] = 'no-cache'
     if token_params[:grant_type] == 'authorization_code'
-      @access_token, @refresh_token = Authorization.find_by!(code: token_params[:code]).exchange
+      @access_token, @refresh_token = Authorization.active.find_by!(code: token_params[:code]).exchange
     end
     render formats: :json
   rescue StandardError => error
app/models/authorization.rb
@@ -6,6 +6,10 @@ class Authorization < ApplicationRecord
   belongs_to :client
   has_many :tokens
 
+  scope :active, ->{ where.not(id: revoked.or(where(id: expired))) }
+  scope :revoked, ->{ where('revoked_at < ?', DateTime.now) }
+  scope :expired, ->{ where('expired_at < ?', DateTime.now) }
+
   after_initialize do
     self.expired_at = 10.minutes.from_now unless expired_at.present?
   end
spec/models/authorization_spec.rb
@@ -20,4 +20,15 @@ RSpec.describe Authorization, type: :model do
       end
     end
   end
+
+  describe ".active, .revoked, .expired" do
+    subject { described_class }
+    let!(:active) { create(:authorization) }
+    let!(:expired) { create(:authorization, expired_at: 1.second.ago) }
+    let!(:revoked) { create(:authorization, revoked_at: 1.second.ago) }
+
+    specify { expect(subject.active).to match_array([active]) }
+    specify { expect(subject.expired).to match_array([expired]) }
+    specify { expect(subject.revoked).to match_array([revoked]) }
+  end
 end
spec/requests/oauth_spec.rb
@@ -55,12 +55,9 @@ RSpec.describe '/oauth' do
   describe "POST /oauth/token" do
     context "when exchanging a code for a token" do
       context "when the code is still valid" do
-        let(:authorization) { create(:authorization, client: client, user: user) }
-        let(:client) { create(:client) }
-        let(:user) { create(:user) }
-        let(:code) { authorization.code }
+        let(:authorization) { create(:authorization) }
 
-        before { post '/oauth/token', params: { grant_type: 'authorization_code', code: code } }
+        before { post '/oauth/token', params: { grant_type: 'authorization_code', code: authorization.code } }
 
         specify { expect(response).to have_http_status(:ok) }
         specify { expect(response.headers['Content-Type']).to include('application/json') }
@@ -75,6 +72,20 @@ RSpec.describe '/oauth' do
         specify { expect(authorization.reload).to be_revoked }
       end
 
+      context "when the code is expired" do
+        let(:authorization) { create(:authorization, expired_at: 1.second.ago) }
+
+        before { post '/oauth/token', params: { grant_type: 'authorization_code', code: authorization.code } }
+
+        specify { expect(response).to have_http_status(:bad_request) }
+        specify { expect(response.headers['Content-Type']).to include('application/json') }
+        specify { expect(response.headers['Cache-Control']).to include('no-store') }
+        specify { expect(response.headers['Pragma']).to eql('no-cache') }
+
+        let(:json) { JSON.parse(response.body, symbolize_names: true) }
+        specify { expect(json[:error]).to eql('invalid_request') }
+      end
+
       context "when the code is not known" do
         before { post '/oauth/token', params: { grant_type: 'authorization_code', code: SecureRandom.hex(20) } }