Here, we have a single policy. The first argument to `policy` is the "condition". If the condition is true,
then the policy applies to the request. If a given policy applies, then one of the checks inside the policy must authorize that policy. _Every policy that applies_ to a given request must each be authorized for a request to be authorized.
Within this policy we have a single check, declared with `authorize_if`. Checks logically apply from top to bottom, based on their check type. In this case, we'd read the policy as "this policy always applies, and authorizes always".
There are four check types, all of which do what they sound like they do:
-`authorize_if` - if the check is true, the policy is authorized.
-`authorize_unless` - if the check is false, the policy is authorized.
-`forbid_if` - if the check is true, the policy is forbidden.
-`forbid_unless` - if the check is false, the policy is forbidden.
In each case, if the policy is not authorized or forbidden, the flow moves to the next check.
### A realistic policy
In this example, we use some of the provided built in checks.
```elixir
policies do
# Anything you can use in a condition, you can use in a check, and vice-versa
# This policy applies if the actor is a super_user
# Additionally, this policy is declared as a `bypass`. That means that this check is allowed to fail without
# failing the whole request, and that if this check *passes*, the entire request passes.
bypass actor_attribute_equals(:super_user, true) do
authorize_if always()
end
# This will likely be a common occurrence. Specifically, policies that apply to all read actions
policy action_type(:read) do
# unless the actor is an active user, forbid their request
A simple way to define a policy is by using `expr/1` in the policy. For example:
```elixir
authorize_if expr(exists(role, name == "owner"))
```
In these and in other filter checks, it is advised to use `exists/2` when referring to relationships, because of the way that the policy authorizer may mix & match your policies when building filters. Depending on the action type these expressions behave slightly differently.
- In reads, the expression will be applied to the query.
- For creates, the expression applies to the result of *applying* the changes. In these cases, you can't use things like `fragment` because nothing exists in the database.
- For updates and destroys, the expression applies to the data *about* to be updated or destroyed
The default access type is `:filter`. In most cases this will be all you need. In the example above, if a user made a request for all instances
of the resource, it wouldn't actually return a forbidden error. It simply attaches the appropriate filter to fetch data that the user can see.
If the actor attribute `active` was `false`, then the request _would_ be forbidden (because there is no data for which they can pass this policy). However, if `active` is `true`, the authorizer would attach the following filter to the request:
Additionally, some checks have more expensive components that can't be checked before the request is run. To enable those, use the `access_type :runtime`. All checks that can be implemented as filters or strict checks will still be done that way, but this enables checks to run their `check/4` callback if necessary.
See `Ash.Policy.Check` for more information on writing custom checks, which you will likely need at some point when the built in checks are insufficient
## Policy Breakdowns
## Explanation
Policy breakdowns can be fetched on demand for a given forbidden error (either an `Ash.Error.Forbidden` that contains one ore more `Ash.Error.Forbidden.Policy`
errors, or an `Ash.Error.Forbidden.Policy` error itself), via `Ash.Policy.Forbidden.Error.report/2`.
Here is an example policy breakdown from tests:
```text
Policy Breakdown
A check status of `?` implies that the solver did not need to determine that check.
Some checks may look like they failed when in reality there was simply no need to check them.
Look for policies with `✘` and `✓` in check statuses.
A check with a `⬇` means that it didn't determine if the policy was authorized or forbidden, and so moved on to the next check.
`🌟` and `⛔` mean that the check was responsible for producing an authorized or forbidden (respectively) status.
If no check results in a status (they all have `⬇`) then the policy is assumed to have failed. In some cases, however, the policy
may have just been ignored, as described above.
Admins and managers can create posts | ⛔:
authorize if: actor.admin == true | ✘ | ⬇
authorize if: actor.manager == true | ✘ | ⬇
```
To remove the help text, you can pass the `help_text?: false` option, which would leave you with:
```text
Policy Breakdown
Admins and managers can create posts | ⛔:
authorize if: actor.admin == true | ✘ | ⬇
authorize if: actor.manager == true | ✘ | ⬇
```
## Including in error message
### **IMPORTANT WARNING**
The following configuration should only ever be used in development mode!
### Instructions
For security reasons, authorization errors don't include any extra information, aside from `forbidden`. To have authorization errors include a policy breakdown (without help text)