Step 1: update Ash Step 2: mass rename Api to Domain Step 3: Ash.Query.expr -> Ash.Expr.expr Also change ref interpolation Step 4: remove all warnings Step 5: remove registries from tests Step 6: fix filter Step 7: private? -> !public? Step 8: Ash.Calculation -> Ash.Resource.Calculation Step 9: use depend_on_resources/1 -> resources/1 Step 10: add Domain to all resources Step 11: use Ash module for all actions Step 12: add public? true all around Step 13: remove verbose? from options passed during Domain calls Step 14: add simple_sat Step 15: Ash.ErrorKind is no more, so remove code from errors Step 16: sprinkle default_accept :* around tests Step 17: replace Ash.Changeset.new/2 with Ash.Changeset.for_* Step 18: calculation fixups - Context is now a struct and arguments go under the arguments key - Function based calculations receive a list of records - Add a select to query-based loads - select -> load Step 19: pass the correct name to pass the policy in tests Step 20: Ash.Query.new/2 is no more Step 21: add AshGraphql.Resource.embedded? utility function Use that instead of Ash.Type.embedded_type?(resource_or_type) since resources are not types anymore Step 22: handle struct + instance_of: Resource in unions Resources are not type anymore so they need to be passed this way in unions Step 23: ensure we only check GraphQL actions for pagination All reads are now paginated by default, so this triggered a compilation error Step 24: swap arguments for sort on calculations Step 25: remove unused debug? option
2.6 KiB
Authorize with GraphQL
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.:ash_context
- a map of arbitrary context to be passed into the changeset/query. Accessible viachangeset.context
andquery.context
By default, authorize?
in the domain is set to true. To disable authorization for a given domain in graphql, use:
graphql do
authorize? false
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 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.
defmodule MyAppWeb.Router do
pipeline :api do
# ...
plug :get_actor_from_token
plug AshGraphql.Plug
end
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
conn
|> set_actor(user)
else
_ -> conn
end
end
end
Policy Breakdowns
By default, unauthorized requests simply return forbidden
in the message. If you prefer to show policy breakdowns in your GraphQL errors, you can set the config option:
config :ash_graphql, :policies, show_policy_breakdowns?: true
{
"data": {
"attendanceRecords": null
},
"errors": [
{
"code": "forbidden",
"fields": [],
"locations": [
{
"column": 3,
"line": 2
}
],
"message": "MyApp.Authentication.User.read\n\n\n\n\nPolicy Breakdown\n Policy | ⛔:\n forbid unless: actor is active | ✓ | ⬇ \n authorize if: actor is Executive | ✘ | ⬇",
"path": [
"attendanceRecords"
],
"short_message": "forbidden",
"vars": {}
}
]
}
Be careful, as this can be an attack vector in some systems (i.e "here is exactly what you need to make true to do what you want to do").