Commit a6030bb

mo <mo.khan@gmail.com>
2018-09-18 21:11:08
RFC 7662: token introspection endpoint.
1 parent d7f69a7
Changed files (3)
app
config
spec
app/controllers/tokens_controller.rb
@@ -13,6 +13,11 @@ class TokensController < ApplicationController
     bad_request
   end
 
+  def introspect
+    claims = Token.claims_for(params[:token], token_type: :any)
+    render json: claims.merge(active: true), status: :ok
+  end
+
   private
 
   attr_reader :current_client
config/routes.rb
@@ -3,15 +3,17 @@ Rails.application.routes.draw do
   post "/session/logout" => "sessions#destroy", as: :logout
   post "/session/new" => "sessions#new"
   post '/oauth/token', to: 'tokens#create'
-  resource :metadata, only: [:show]
   resource :mfa, only: [:new, :create]
-  resource :response, only: [:show]
-  resource :session, only: [:new, :create, :destroy]
+  resource :metadata, only: [:show]
   resource :oauth, only: [:show, :create] do
     get :authorize, to: "oauths#show"
   end
-  resource :tokens, only: [:create]
+  resource :session, only: [:new, :create, :destroy]
   resources :registrations, only: [:new, :create]
+  resource :response, only: [:show]
+  resource :tokens, only: [:create] do
+    post :introspect
+  end
 
   namespace :my do
     resource :dashboard, only: [:show]
spec/requests/tokens_spec.rb
@@ -1,11 +1,11 @@
 require 'rails_helper'
 
 RSpec.describe '/tokens' do
-  describe "POST /oauth/token" do
-    let(:client) { create(:client) }
-    let(:credentials) { ActionController::HttpAuthentication::Basic.encode_credentials(client.uuid, client.secret) }
-    let(:headers) { { 'Authorization' => credentials } }
+  let(:client) { create(:client) }
+  let(:credentials) { ActionController::HttpAuthentication::Basic.encode_credentials(client.uuid, client.secret) }
+  let(:headers) { { 'Authorization' => credentials } }
 
+  describe "POST /oauth/token" do
     context "when using the authorization_code grant" do
       context "when the code is still valid" do
         let(:authorization) { create(:authorization, client: client) }
@@ -225,4 +225,38 @@ RSpec.describe '/tokens' do
       specify { expect(json[:error]).to eql('invalid_request') }
     end
   end
+
+  describe "POST /tokens/introspect" do
+    context "when the access_token is valid" do
+      let(:token) { create(:access_token) }
+
+      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(true) }
+      specify { expect(json[:sub]).to eql(token.claims[:sub]) }
+      specify { expect(json[:aud]).to eql(token.claims[:aud]) }
+      specify { expect(json[:iss]).to eql(token.claims[:iss]) }
+      specify { expect(json[:exp]).to eql(token.claims[:exp]) }
+      specify { expect(json[:iat]).to eql(token.claims[:iat]) }
+    end
+
+    context "when the refresh_token is valid" do
+      let(:token) { create(:refresh_token) }
+
+      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(true) }
+      specify { expect(json[:sub]).to eql(token.claims[:sub]) }
+      specify { expect(json[:aud]).to eql(token.claims[:aud]) }
+      specify { expect(json[:iss]).to eql(token.claims[:iss]) }
+      specify { expect(json[:exp]).to eql(token.claims[:exp]) }
+      specify { expect(json[:iat]).to eql(token.claims[:iat]) }
+    end
+  end
 end