You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/spec/requests/mcp_oauth_spec.rb

86 lines
2.5 KiB

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'MCP endpoint authentication', type: :request do
let(:account) { create(:account) }
let(:user) { create(:user, account:) }
before do
create(:account_config, account:, key: AccountConfig::ENABLE_MCP_KEY, value: true)
end
def post_mcp(token)
post '/mcp',
params: { jsonrpc: '2.0', method: 'ping', id: 1 }.to_json,
headers: { 'Authorization' => "Bearer #{token}", 'Content-Type' => 'application/json' }
end
context 'unauthenticated' do
it 'returns 401 with RFC 9728 WWW-Authenticate header' do
post '/mcp', params: '{}', headers: { 'Content-Type' => 'application/json' }
expect(response).to have_http_status(:unauthorized)
expect(response.headers['WWW-Authenticate']).to match(
%r{\ABearer resource_metadata="http://www\.example\.com/\.well-known/oauth-protected-resource", error="invalid_token"\z}
)
end
end
context 'with a valid OAuth access token' do
let(:access_token) do
create(:oauth_access_token, resource_owner_id: user.id, scopes: 'mcp')
end
it 'succeeds and dispatches to HandleRequest' do
post_mcp(access_token.plaintext_token)
expect(response).to have_http_status(:ok).or have_http_status(:accepted)
end
end
context 'with an expired OAuth token' do
it 'returns 401' do
token = create(:oauth_access_token, resource_owner_id: user.id, scopes: 'mcp', expires_in: 1)
travel_to(2.hours.from_now) do
post_mcp(token.plaintext_token)
expect(response).to have_http_status(:unauthorized)
end
end
end
context 'with a revoked OAuth token' do
let(:access_token) do
create(:oauth_access_token, resource_owner_id: user.id, scopes: 'mcp',
revoked_at: 1.minute.ago)
end
it 'returns 401' do
post_mcp(access_token.plaintext_token)
expect(response).to have_http_status(:unauthorized)
end
end
context 'with an OAuth token lacking the mcp scope' do
let(:access_token) do
create(:oauth_access_token, resource_owner_id: user.id, scopes: 'other')
end
it 'returns 401' do
post_mcp(access_token.plaintext_token)
expect(response).to have_http_status(:unauthorized)
end
end
context 'with a legacy McpToken bearer (back-compat)' do
it 'still succeeds' do
token = build(:mcp_token, user:)
raw = token.token
token.save!
post_mcp(raw)
expect(response).to have_http_status(:ok).or have_http_status(:accepted)
end
end
end