Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save churcho/f7d72e90e2b0819a262f109a3fef9d92 to your computer and use it in GitHub Desktop.
Save churcho/f7d72e90e2b0819a262f109a3fef9d92 to your computer and use it in GitHub Desktop.
Disable GraphQL schema introspection in Elixir Absinthe using a plugin
defmodule MyAppWeb.Schema.Middleware.AuthorizedIntrospection do
@moduledoc """
Disable or restrict schema introspection to authorized requests
"""
@behaviour Absinthe.Plugin
@impl Absinthe.Plugin
def before_resolution(%{context: %{admin: true}} = exec), do: exec
def before_resolution(exec) do
if Enum.find(exec.result.emitter.selections, fn %{name: field_name} ->
Macro.underscore(field_name) == "__schema"
end) do
%{
exec
| validation_errors: [
%Absinthe.Phase.Error{message: "Unauthorized", phase: __MODULE__}
]
}
else
exec
end
end
@impl Absinthe.Plugin
def after_resolution(exec), do: exec
@impl Absinthe.Plugin
def pipeline(pipeline, _exec), do: pipeline
end
defmodule MyAppWeb.Schema.Fixtures.TestSchema do
use Absinthe.Schema
query do
field(:test, :integer, resolve: fn _, _ -> {:ok, 1} end)
end
def plugins do
[MyAppWeb.Schema.Middleware.AuthorizedIntrospection | Absinthe.Plugin.defaults()]
end
end
defmodule MyAppWeb.Schema.Middleware.AuthorizedIntrospectionTest do
use ExUnit.Case, async: true
@schema MyAppWeb.Schema.Fixtures.TestSchema
@query """
query {
test
}
"""
@schema_query """
query {
test
__schema {
types {
name
}
}
}
"""
@schema_query_alt_case """
query {
test
_Schema {
types {
name
}
}
}
"""
describe "allow query without introspection" do
test "returns data" do
assert {:ok, %{data: %{"test" => 1}}} =
Absinthe.run(@query, @schema, context: %{admin: false})
end
end
describe "prevent unauthorized introspection" do
test "returns unauthorized and no data" do
assert {:ok, %{errors: [%{message: "Unauthorized"}]}} ==
Absinthe.run(@schema_query, @schema, context: %{admin: false})
end
test "alt case, returns unauthorized and no data" do
assert {:ok, %{errors: [%{message: "Unauthorized"}]}} ==
Absinthe.run(@schema_query_alt_case, @schema, context: %{admin: false})
end
end
describe "allow authorized introspection" do
test "returns data and schema" do
assert {:ok, %{data: %{"test" => 1, "__schema" => _}}} =
Absinthe.run(@schema_query, @schema, context: %{admin: true})
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment