FEATURE: Allow plugins to register parameter-based API routes (#10505)

FEATURE: Allow plugins to register parameter-based API routes (#10505)

Example usage:

add_api_parameter_route(
  method: :get,
  route: "users#bookmarks",
  format: :ics
)
diff --git a/lib/auth/default_current_user_provider.rb b/lib/auth/default_current_user_provider.rb
index f20b056..30a8ff8 100644
--- a/lib/auth/default_current_user_provider.rb
+++ b/lib/auth/default_current_user_provider.rb
@@ -359,6 +359,10 @@ class Auth::DefaultCurrentUserProvider
 
   private
 
+  def parameter_api_patterns
+    PARAMETER_API_PATTERNS + DiscoursePluginRegistry.api_parameter_routes
+  end
+
   # By default we only allow headers for sending API credentials
   # However, in some scenarios it is essential to send them via url parameters
   # so we need to add some exceptions
@@ -369,7 +373,7 @@ class Auth::DefaultCurrentUserProvider
     path_params = @env['action_dispatch.request.path_parameters']
     request_route = "#{path_params[:controller]}##{path_params[:action]}" if path_params
 
-    PARAMETER_API_PATTERNS.any? do |p|
+    parameter_api_patterns.any? do |p|
       (p[:method] == "*" || Array(p[:method]).include?(request_method)) &&
       (p[:format] == "*" || Array(p[:format]).include?(request_format)) &&
       (p[:route] == "*" || Array(p[:route]).include?(request_route))
diff --git a/lib/discourse_plugin_registry.rb b/lib/discourse_plugin_registry.rb
index 335d102..93e2c11 100644
--- a/lib/discourse_plugin_registry.rb
+++ b/lib/discourse_plugin_registry.rb
@@ -79,6 +79,7 @@ class DiscoursePluginRegistry
 
   define_filtered_register :topic_thumbnail_sizes
 
+  define_filtered_register :api_parameter_routes
   define_filtered_register :api_key_scope_mappings
 
   def self.register_auth_provider(auth_provider)
diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb
index 0ca72b1..e0dec5f 100644
--- a/lib/plugin/instance.rb
+++ b/lib/plugin/instance.rb
@@ -782,6 +782,21 @@ class Plugin::Instance
     DiscoursePluginRegistry.register_api_key_scope_mapping({ resource => action }, self)
   end
 
+  # Register a route which can be authenticated using an api key or user api key
+  # in a query parameter rather than a header. For example:
+  #
+  # add_api_parameter_route(
+  #   method: :get,
+  #   route: "users#bookmarks",
+  #   format: :ics
+  # )
+  #
+  # See Auth::DefaultCurrentUserProvider::PARAMETER_API_PATTERNS for more examples
+  # and Auth::DefaultCurrentUserProvider#api_parameter_allowed? for implementation
+  def add_api_parameter_route(method:, route:, format:)
+    DiscoursePluginRegistry.register_api_parameter_route({ method: method, route: route, format: format }, self)
+  end
+
   protected
 
   def self.js_path
diff --git a/spec/integration/api_keys_spec.rb b/spec/integration/api_keys_spec.rb
index 4517687..d74378c 100644
--- a/spec/integration/api_keys_spec.rb
+++ b/spec/integration/api_keys_spec.rb
@@ -48,6 +48,19 @@ describe 'api keys' do
     expect(response.status).to eq(302)
   end
 
+  context "with a plugin registered filter" do
+    before do
+      plugin = Plugin::Instance.new
+      plugin.add_api_parameter_route method: :get, route: "session#current", format: "*"
+    end
+
+    it 'allows parameter access to the registered route' do
+      get '/session/current.json', params: {
+        api_key: api_key.key
+      }
+      expect(response.status).to eq(200)
+    end
+  end
 end
 
 describe 'user api keys' do

GitHub sha: 629ee549

This commit appears in #10505 which was approved by pmusaraj. It was merged by davidtaylorhq.