Commit d6354d6
Changed files (4)
app
controllers
config
environments
spec
requests
app/controllers/tokens_controller.rb
@@ -15,7 +15,11 @@ class TokensController < ApplicationController
def introspect
claims = Token.claims_for(params[:token], token_type: :any)
- render json: claims.merge(active: true), status: :ok
+ if revoked_tokens[claims[:jti]]
+ render json: { active: false }, status: :ok
+ else
+ render json: claims.merge(active: true), status: :ok
+ end
end
private
@@ -77,4 +81,10 @@ class TokensController < ApplicationController
assertion_grant
end
end
+
+ def revoked_tokens
+ Rails.cache.fetch("revoked-tokens", expires_in: 10.minutes) do
+ Hash[Token.revoked.pluck(:uuid).map { |x| [x, true] }]
+ end
+ end
end
config/environments/test.rb
@@ -46,5 +46,6 @@ Rails.application.configure do
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
+ config.cache_store = :null_store
end
Rails.application.default_url_options = { host: 'www.example.com' }
spec/requests/tokens_spec.rb
@@ -258,5 +258,16 @@ RSpec.describe '/tokens' do
specify { expect(json[:exp]).to eql(token.claims[:exp]) }
specify { expect(json[:iat]).to eql(token.claims[:iat]) }
end
+
+ context "when the token is revoked" do
+ let(:token) { create(:access_token, :revoked) }
+
+ before { post '/tokens/introspect', params: { token: token.to_jwt }, headers: headers }
+
+ specify { expect(response).to have_http_status(:ok) }
+ specify { expect(response['Content-Type']).to include('application/json') }
+ let(:json) { JSON.parse(response.body, symbolize_names: true) }
+ specify { expect(json[:active]).to eql(false) }
+ end
end
end
spec/factories.rb
@@ -15,6 +15,10 @@ FactoryBot.define do
factory :refresh_token do
token_type { :refresh }
end
+
+ trait :revoked do
+ revoked_at { Time.now }
+ end
end
factory :authorization do