feat(AshGraphql.Plug): Support standard actor/tenant configuration. (#43)

This commit is contained in:
James Harton 2022-10-31 10:49:24 +13:00 committed by GitHub
parent d3419ebdbc
commit 57e42cac6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 179 additions and 34 deletions

View file

@ -18,7 +18,7 @@ jobs:
matrix:
otp: ["23"]
elixir: ["1.14.0"]
ash: ["main", "2.2.0"]
ash: ["main", "2.3.0"]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ASH_VERSION: ${{matrix.ash}}

View file

@ -1,8 +1,9 @@
# Authorize with Graphql
AshGraphql uses two special keys in the `absinthe` context:
AshGraphql uses three special keys in the `absinthe` context:
* `:actor` - the current actor, to be used for authorization/preparations/changes
* `:tenant` - a tenant when using [multitenancy](https://ash-hq.org/docs/guides/ash/latest/topics/multitenancy.md).
* `:ash_context` - a map of arbitrary context to be passed into the changeset/query. Accessible via `changeset.context` and `query.context`
By default, `authorize?` in the api is set to true. To disable authorization for a given API in graphql, use:
@ -14,32 +15,39 @@ end
```
If you are doing authorization, you'll need to provide an `actor`.
To set the `actor` for authorization, you'll need to add an `actor` key to the absinthe context. Typically, you would have a plug that fetches the current user, and in that plug you could set the absinthe context. For example:
To set the `actor` for authorization, you'll need to add an `actor` key to the
absinthe context. Typically, you would have a plug that fetches the current user
and uses `Ash.PlugHelpers.set_actor/2` to set the actor in the `conn` (likewise
with `Ash.PlugHelpers.set_tenant/2`).
Just add `AshGraphql.Plug` somewhere _after_ that in the pipeline and the your
GraphQL APIs will have the correct authorization.
```elixir
defmodule MyAppWeb.UserPlug do
@behaviour Plug
import Plug.Conn
def init(opts), do: opts
def call(conn, _) do
case build_context(conn) do
{:ok, context} ->
put_private(conn, :absinthe, %{context: context})
_ ->
conn
end
defmodule MyAppWeb.Router do
pipeline :api do
# ...
plug :get_actor_from_token
plug AshGraphql.Plug
end
defp build_context(conn) do
with ["" <> token] <- get_req_header(conn, "authorization"),
scope "/" do
forward "/gql", Absinthe.Plug, schema: YourSchema
forward "/playground",
Absinthe.Plug.GraphiQL,
schema: YourSchema,
interface: :playground
end
def get_actor_from_token(conn, _opts) do
with ["" <> token] <- get_req_header(conn, "authorization"),
{:ok, user, _claims} <- MyApp.Guardian.resource_from_token(token) do
# ash_context allows you to pass arbitrary data down into the changeset/query context
# This can be accessed at `changeset.context` or `query.context`.
{:ok, %{actor: user, ash_context: %{some: :data}}}
conn
|> set_actor(user)
else
_ -> conn
end
end
end

30
lib/plug.ex Normal file
View file

@ -0,0 +1,30 @@
defmodule AshGraphql.Plug do
@moduledoc """
Automatically set up the GraphQL `actor` and `tenant`.
Adding this plug to your pipeline will automatically set the `actor` and
`tenant` if they were previously put there by `Ash.PlugHelpers.set_actor/2` or
`Ash.PlugHelpers.set_tenant/2`.
"""
@behaviour Plug
alias Ash.PlugHelpers
alias Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
actor = PlugHelpers.get_actor(conn)
tenant = PlugHelpers.get_tenant(conn)
absinthe = Map.get(conn.private, :absinthe, %{})
context =
absinthe
|> Map.get(:context, %{})
|> Map.merge(%{actor: actor, tenant: tenant})
absinthe = Map.put(absinthe, :context, context)
Conn.put_private(conn, :absinthe, absinthe)
end
end

View file

@ -115,7 +115,7 @@ defmodule AshGraphql.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:ash, ash_version("~> 2.2")},
{:ash, ash_version("~> 2.3")},
{:absinthe_plug, "~> 1.4"},
{:absinthe, "~> 1.7"},
{:dataloader, "~> 1.0"},

View file

@ -1,11 +1,9 @@
%{
"absinthe": {:hex, :absinthe, "1.7.0", "36819e7b1fd5046c9c734f27fe7e564aed3bda59f0354c37cd2df88fd32dd014", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "566a5b5519afc9b29c4d367f0c6768162de3ec03e9bf9916f9dc2bcbe7c09643"},
"absinthe_plug": {:hex, :absinthe_plug, "1.5.5", "be913e77df1947ffb654a1cf1a90e28d84dc23241f6404053750bae513ccd52b", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "6c366615d9422444774206aff3448bb9cfb4e849e0c9a94a275085097bc67509"},
"ash": {:hex, :ash, "2.2.0", "4fdc0fef5afb3f5045b1ca4e1ccb139b9f703cbc7c21dc645e32ac9582b11f63", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: true]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8.0", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:spark, "~> 0.1 and >= 0.1.28", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.5.0", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "48eca587e7076fe4f8547e919c0712f081ce85e66c316f6f51dd2535ad046013"},
"ashton": {:hex, :ashton, "0.4.1", "d0f7782ac44fa22da7ce544028ee3d2078592a834d8adf3e5b4b6aeb94413a55", [:mix], [], "hexpm", "24db667932517fdbc3f2dae777f28b8d87629271387d4490bc4ae8d9c46ff3d3"},
"ash": {:hex, :ash, "2.3.0", "3f47a8f1f273a8fce66ac48ef146f4f7a51a6e50d26f50c2f650fbb976e6f5a8", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: true]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8.0", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:spark, "~> 0.2", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.5.0", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1540d43533b2c9caa9602209035f33ec2e32240df53d289fc196766dc0e3b510"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"},
"credo": {:hex, :credo, "1.6.4", "ddd474afb6e8c240313f3a7b0d025cc3213f0d171879429bf8535d7021d9ad78", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "c28f910b61e1ff829bffa056ef7293a8db50e87f2c57a9b5c3f57eee124536b7"},
"dataloader": {:hex, :dataloader, "1.0.10", "a42f07641b1a0572e0b21a2a5ae1be11da486a6790f3d0d14512d96ff3e3bbe9", [:mix], [{:ecto, ">= 3.4.3 and < 4.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "54cd70cec09addf4b2ace14cc186a283a149fd4d3ec5475b155951bf33cd963f"},
@ -20,14 +18,11 @@
"ex_doc": {:hex, :ex_doc, "0.23.0", "a069bc9b0bf8efe323ecde8c0d62afc13d308b1fa3d228b65bca5cf8703a529d", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "f5e2c4702468b2fd11b10d39416ddadd2fcdd173ba2a0285ebd92c39827a5a16"},
"excoveralls": {:hex, :excoveralls, "0.13.4", "7b0baee01fe150ef81153e6ffc0fc68214737f54570dc257b3ca4da8e419b812", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "faae00b3eee35cdf0342c10b669a7c91f942728217d2a7c7f644b24d391e6190"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"gettext": {:hex, :gettext, "0.20.0", "75ad71de05f2ef56991dbae224d35c68b098dd0e26918def5bb45591d5c8d429", [:mix], [], "hexpm", "1c03b177435e93a47441d7f681a7040bd2a816ece9e2666d1c9001035121eb3d"},
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
"git_ops": {:hex, :git_ops, "2.5.1", "94ab6e3bc69fe765a62cbdb09969016613a154dec8fc4f6ebae682f030451da9", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "1219edc8810dcea40472ec5b7ed04786a9e1b0e4e49d8642b0e1cdfb8a6ad261"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"libgraph": {:hex, :libgraph, "0.13.3", "20732b7bafb933dcf7351c479e03076ebd14a85fd3202c67a1c197f4f7c2466b", [:mix], [], "hexpm", "78f2576eef615440b46f10060b1de1c86640441422832052686df53dc3c148c6"},
"machinery": {:hex, :machinery, "1.0.0", "df6968d84c651b9971a33871c78c10157b6e13e4f3390b0bee5b0e8bdea8c781", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "4f6eb4185a48e7245360bedf653af4acc6fa6ae8ff4690619395543fa1a8395f"},
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
"makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
@ -41,12 +36,10 @@
"plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
"sobelow": {:hex, :sobelow, "0.11.0", "cdc17e3a9f1ea78dc55dbe0a03121cb6767fef737c6d9f1e62ee7e78730abccc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "c57807bfe6f231338b657781f89ef0320b66a0dbe779aa911d6ed27cfa14ae6e"},
"sourceror": {:hex, :sourceror, "0.11.2", "549ce48be666421ac60cfb7f59c8752e0d393baa0b14d06271d3f6a8c1b027ab", [:mix], [], "hexpm", "9ab659118896a36be6eec68ff7b0674cba372fc8e210b1e9dc8cf2b55bb70dfb"},
"spark": {:hex, :spark, "0.1.28", "8ce732daa56ad0dc11190b28461f85e71b67c5b61ce4818841bc8fcdbf799676", [:mix], [{:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "11b2d52b473345e2ecb4fe70c76ca8400b2fa9417acb629a6bd92db9d3ff953b"},
"spark": {:hex, :spark, "0.2.3", "3678177ca1f1f4c7919da90b49f5e378c39e1bdf2f59ad8909c0c3591fe8dbb6", [:mix], [{:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "933dadc7fcce93198104e7d88243772bbde9e54b001929a4c04bc733812e8e3b"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"},
"telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
"timex": {:hex, :timex, "3.7.9", "790cdfc4acfce434e442f98c02ea6d84d0239073bfd668968f82ac63e9a6788d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "64691582e5bb87130f721fc709acfb70f24405833998fabf35be968984860ce1"},
"typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
}

114
test/plug_test.exs Normal file
View file

@ -0,0 +1,114 @@
defmodule AshGraphql.PlugTest do
@moduledoc false
use ExUnit.Case, async: false
require Ash.Query
import Plug.Conn
@moduletag capture_log: true
setup do
on_exit(fn ->
AshGraphql.TestHelpers.stop_ets()
end)
end
defmodule Pipeline do
@moduledoc false
use Plug.Router
plug(Plug.Parsers, parsers: [:urlencoded, :multipart, :json], json_decoder: Jason)
plug(AshGraphql.Plug)
plug(:match)
plug(:dispatch)
forward("/", to: Absinthe.Plug, init_opts: [schema: AshGraphql.Test.Schema])
end
test "when the actor is set, the current user returns the correct value" do
user =
AshGraphql.Test.User
|> Ash.Changeset.for_create(:create, %{name: "Marty McFly"})
|> AshGraphql.Test.Api.create!()
resp =
"""
query {
currentUser {
id
name
}
}
"""
|> conn()
|> Ash.PlugHelpers.set_actor(user)
|> run()
assert resp["data"]["currentUser"]["id"] == user.id
assert resp["data"]["currentUser"]["name"] == user.name
end
test "when the actor is not set, the current user return nil" do
resp =
"""
query {
currentUser {
id
name
}
}
"""
|> conn()
|> run()
refute resp["data"]["currentUser"]
end
test "when the tenant is set, the the multi tenant tag is correct" do
tenant = "Marty McFly"
tag =
AshGraphql.Test.MultitenantTag
|> Ash.Changeset.for_create(:create, [name: "1985"], tenant: tenant)
|> AshGraphql.Test.Api.create!()
resp =
"""
query MultitenantTag($id: ID!) {
getMultitenantTag(id: $id) {
name
}
}
"""
|> conn(%{id: tag.id})
|> Ash.PlugHelpers.set_tenant(tenant)
|> run()
assert resp["data"]["getMultitenantTag"]["name"] == "1985"
end
test "when the tenant is not set, the multi tennant tag is nil" do
resp =
"""
query MultitenantTag($id: ID!) {
getMultitenantTag(id: $id) {
name
}
}
"""
|> conn(%{id: Ecto.UUID.generate()})
|> run()
refute resp["data"]["getMultitenantTag"]
end
def conn(query, variables \\ %{}) do
:post
|> Plug.Test.conn("/", %{query: query, variables: variables})
|> put_req_header("content-type", "application/json")
end
def run(conn) do
conn
|> Pipeline.call([])
|> Map.fetch!(:resp_body)
|> Jason.decode!()
end
end

View file

@ -10,7 +10,7 @@ defmodule AshGraphql.Test.User do
type :user
queries do
read_one :current_user, :current_user, allow_nil?: false
read_one :current_user, :current_user
end
mutations do